bitkeeper revision 1.22.4.1 (3e4a8cb8Aw-XeXojqgYl10tZjNiQyA)
authorsmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>
Wed, 12 Feb 2003 18:04:40 +0000 (18:04 +0000)
committersmh22@boulderdash.cl.cam.ac.uk <smh22@boulderdash.cl.cam.ac.uk>
Wed, 12 Feb 2003 18:04:40 +0000 (18:04 +0000)
Initial 'debugging' support (aka keyboard and serial rx int handlers :-)
Also current state of Alex's IDE stuff (not yet completely working). You
need to config this up to use it.

16 files changed:
.rootkeys
BitKeeper/etc/ignore
xen-2.4.16/drivers/block/xen_block.c [new file with mode: 0644]
xen-2.4.16/drivers/char/Makefile [new file with mode: 0644]
xen-2.4.16/drivers/char/xen_kbd.c [new file with mode: 0644]
xen-2.4.16/drivers/char/xen_serial.c [new file with mode: 0644]
xen-2.4.16/drivers/ide/ide-disk.c.orig [new file with mode: 0644]
xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c [new file with mode: 0644]
xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c [new file with mode: 0644]
xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c [new file with mode: 0644]
xenolinux-2.4.16-sparse/drivers/block/Config.in [new file with mode: 0644]
xenolinux-2.4.16-sparse/fs/partitions/check.c [new file with mode: 0644]
xenolinux-2.4.16-sparse/fs/partitions/msdos.c [new file with mode: 0644]
xenolinux-2.4.16-sparse/include/linux/blk.h [new file with mode: 0644]
xenolinux-2.4.16-sparse/include/linux/major.h [new file with mode: 0644]
xenolinux-2.4.16-sparse/init/main.c [new file with mode: 0644]

index 2304c74597e8c0624892cf1855b2d3c9265b71b3..0ffb115edb000bacd5a94d7c67242742bd12f870 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79beME_0abStePF6fU8XLuQnWw xen-2.4.16/drivers/block/elevator.c
 3ddb79beNQVrdGyoI4njXhgAjD6a4A xen-2.4.16/drivers/block/genhd.c
 3ddb79beyWwLRP_BiM2t1JKgr_plEw xen-2.4.16/drivers/block/ll_rw_blk.c
+3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen-2.4.16/drivers/block/xen_block.c
+3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen-2.4.16/drivers/char/Makefile
+3e4a8cb7WmiYdC-ASGiCSG_CL8vsqg xen-2.4.16/drivers/char/xen_kbd.c
+3e4a8cb7nMChlro4wvOBo76n__iCFA xen-2.4.16/drivers/char/xen_serial.c
 3ddb79bdhcqD9ebrslr0O0oHqTiiXg xen-2.4.16/drivers/ide/Makefile
 3ddb79bdErDn_WC3G-fWxKNR3viLnA xen-2.4.16/drivers/ide/ide-disk.c
+3e4a8cb7DcFFHW_fG_OHbY_6f3lPWw xen-2.4.16/drivers/ide/ide-disk.c.orig
 3ddb79bdIPNW36FrlId94jTXaW8HoA xen-2.4.16/drivers/ide/ide-dma.c
 3ddb79be5Ysvhn4se_Z-LQY_hI6UPw xen-2.4.16/drivers/ide/ide-features.c
 3ddb79bdh1ohsWYRH_KdaXr7cqs12w xen-2.4.16/drivers/ide/ide-geometry.c
 3ddb79b7v_Be34as7_mlzFlw65hOjQ xenolinux-2.4.16-sparse/arch/xeno/defconfig
 3ddb79b7KUvtx0knQJoRaBDZQeNidg xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile
 3ddb79b6Rc0uAOGFthIFxq1KGWZ_Iw xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c
+3e4a8cb7JECr--r1ipnrkd7NKdbUqQ xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c
+3e4a8cb7SLWsLTXQjv7ng6-3hL4pCA xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c
 3ddb79b7LLVJBGynxHSOh9A9l97sug xenolinux-2.4.16-sparse/arch/xeno/drivers/console/Makefile
 3ddb79b7UG2QiRAU-Wvc1Y_BLigu1Q xenolinux-2.4.16-sparse/arch/xeno/drivers/console/console.c
 3ddb79b75eo4PRXkT6Th9popt_SJhg xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/Makefile
+3e4a8cb79dT0F4q5T4GEqMj4CtAquQ xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c
 3ddb79b7Xyaoep6U0kLvx6Kx7OauDw xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_core.c
 3df9ce13K7qSLBtHV-01QHPW62649Q xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_memory.c
 3ddb79b7PulSkF9m3c7K5MkxHRf4hA xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_ops.h
 3ddb79b83Zj7Xn2QVhU4HeMuAC9FjA xenolinux-2.4.16-sparse/arch/xeno/mm/init.c
 3df9ce13TRWIv0Mawm15zESP7jcT7A xenolinux-2.4.16-sparse/arch/xeno/mm/mmu_context.c
 3ddb79b7aKdTkbr3u6aze8tVwGh_TQ xenolinux-2.4.16-sparse/arch/xeno/vmlinux.lds
+3e4a8cb7lpFFwT1Iu9zXWc8Ew4klFA xenolinux-2.4.16-sparse/drivers/block/Config.in
 3ddb79bbx682YH6vR2zbVOXwg73ULg xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c
 3ddb79bcJfHdwrPsjqgI33_OsGdVCg xenolinux-2.4.16-sparse/drivers/block/rd.c
 3ddb79bcpVu-IbnqwQqpRqsEbLpsuw xenolinux-2.4.16-sparse/drivers/char/tty_io.c
 3e15d5273gfR2fbcYe05kqBSAvCX_w xenolinux-2.4.16-sparse/fs/exec.c
+3e4a8cb7kqfJTMeOpPcYxqxv7N18DA xenolinux-2.4.16-sparse/fs/partitions/check.c
+3e4a8cb7p079Xxly4uNcouacMSjJLw xenolinux-2.4.16-sparse/fs/partitions/msdos.c
 3ddb79b8VFtfWSCrXKPN2K21zd_vtw xenolinux-2.4.16-sparse/include/asm-xeno/a.out.h
 3ddb79b8Zzi13p3OAPV25QgiC3THAQ xenolinux-2.4.16-sparse/include/asm-xeno/apic.h
 3ddb79baZDlsdV_m6C5CXnWMl15p1g xenolinux-2.4.16-sparse/include/asm-xeno/apicdef.h
 3ddb79ba2qYtIQAT_-vCFkkZUXu_UQ xenolinux-2.4.16-sparse/include/asm-xeno/user.h
 3ddb79bbqhb9X9qWOz5Bv4wOzrkITg xenolinux-2.4.16-sparse/include/asm-xeno/vga.h
 3ddb79bbA52x94o6uwDYsbzrH2hjzA xenolinux-2.4.16-sparse/include/asm-xeno/xor.h
+3e4a8cb7ON8EclY3NN3YPXyMT941hA xenolinux-2.4.16-sparse/include/linux/blk.h
+3e4a8cb7GJrKD0z7EF0VZOhdEa01Mw xenolinux-2.4.16-sparse/include/linux/major.h
 3ddb79bb_7YG4U75ZmEic9YXWTW7Vw xenolinux-2.4.16-sparse/include/linux/sunrpc/debug.h
+3e4a8cb7j05wwb1uPZgY16s68o7qAw xenolinux-2.4.16-sparse/init/main.c
 3ddb79bcxkVPfWlZ1PQKvDrfArzOVw xenolinux-2.4.16-sparse/kernel/panic.c
 3ddb79bbP31im-mx2NbfthSeqty1Dg xenolinux-2.4.16-sparse/mk
 3e15d52e0_j129JPvo7xfYGndVFpwQ xenolinux-2.4.16-sparse/mm/memory.c
index 4fe10ce2d4fd725b61470ca060285222aa711ace..e5be6b0ec89b83e8efb28074a0668cec00c3bbe1 100644 (file)
@@ -3,3 +3,19 @@ PENDING/*
 xen-2.4.16/common/kernel.c.old
 xen-2.4.16/common/kernel.c.ok-ish
 xen-2.4.16/size.image
+xen-2.4.16/drivers/block/ll_rw_blk.c.orig
+xen-2.4.16/drivers/ide/ide-disk.c.orig
+xen-2.4.16/drivers/ide/ide-probe.c.orig
+xen-2.4.16/drivers/ide/ide-taskfile.c.orig
+xen-2.4.16/drivers/ide/ide.c.orig
+xen-2.4.16/drivers/net/e1000/e1000.o
+xen-2.4.16/drivers/net/e1000/e1000_ethtool.o
+xen-2.4.16/drivers/net/e1000/e1000_hw.o
+xen-2.4.16/drivers/net/e1000/e1000_main.o
+xen-2.4.16/drivers/net/e1000/e1000_param.o
+xen-2.4.16/include/hypervisor-ifs/block.h.orig
+xen-2.4.16/include/xeno/blkdev.h.orig
+xen-2.4.16/include/xeno/sched.h.orig
+xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile.orig
+xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c.orig
+xenolinux-2.4.16-sparse/scripts/kconfig.tk
diff --git a/xen-2.4.16/drivers/block/xen_block.c b/xen-2.4.16/drivers/block/xen_block.c
new file mode 100644 (file)
index 0000000..b6d0e89
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * xen-block.c
+ *
+ * process incoming block io requests from guestos's.
+ */
+
+#include <xeno/config.h>
+#include <xeno/types.h>
+#include <xeno/lib.h>
+#include <xeno/sched.h>
+#include <xeno/blkdev.h>
+#include <xeno/event.h>                                    /* mark_hyp_event */
+#include <hypervisor-ifs/block.h>
+#include <hypervisor-ifs/hypervisor-if.h>
+#include <asm-i386/io.h>
+#include <asm/spinlock.h>
+
+#define XEN_BLK_DEBUG 0
+#define XEN_BLK_DEBUG_LEVEL KERN_ALERT
+
+#define XEN_BLK_REQUEST_LIST_SIZE 256                      /* very arbitrary */
+
+typedef struct blk_request
+{
+  struct list_head queue;
+  struct buffer_head *bh;
+  blk_ring_entry_t request;
+  struct task_struct *domain;                           /* requesting domain */
+} blk_request_t;
+
+static int pending_work;                  /* which domains have work for us? */
+blk_request_t blk_request_list[XEN_BLK_REQUEST_LIST_SIZE];
+struct list_head free_queue;                              /* unused requests */
+struct list_head pending_queue;                      /* waiting for hardware */
+struct list_head io_done_queue;       /* request completed. send to guest os */
+spinlock_t free_queue_lock;
+spinlock_t pending_queue_lock;
+spinlock_t io_done_queue_lock;
+
+/* some definitions */
+void dumpx (char *buffer, int count);
+void printx (char * string);
+long do_block_io_op_domain (struct task_struct* task);
+int dispatch_rw_block_io (int index);
+int dispatch_probe_block_io (int index);
+int dispatch_debug_block_io (int index);
+
+/*
+ * end_block_io_op
+ *
+ * IO has completed.  Need to notify the guest operating system.
+ * Called from hardware interrupt.
+ */
+
+void end_block_io_op(struct buffer_head * bh)
+{
+  unsigned long cpu_mask;
+  /* struct list_head *list;*/
+  blk_request_t *blk_request = NULL;
+  unsigned long flags;                                           /* irq save */
+
+#if 0
+  printk("{E}"); 
+#endif
+  if (XEN_BLK_DEBUG)  printk(XEN_BLK_DEBUG_LEVEL
+                            "XEN end_block_io_op,  bh: %lx\n",
+                            (unsigned long)bh);
+
+  {
+    char temp[100];
+    sprintf(temp, "endio  bh: 0x%p, blkno: 0x%lx",
+           bh, bh->b_blocknr);
+    printx(temp);
+  }
+
+  spin_lock_irqsave(&pending_queue_lock, flags);
+  /*
+  list_for_each (list, &pending_queue)
+  {
+    blk_request = list_entry(list, blk_request_t, queue);
+    if (blk_request->bh == bh)      
+    {
+      break;
+    }
+  }
+  */
+  blk_request = (blk_request_t *)bh->b_xen_request;
+  if (blk_request == NULL)
+  {
+    printk (KERN_ALERT
+           "   block io interrupt received for unknown buffer [0x%lx]\n",
+           (unsigned long) bh);
+    spin_unlock_irqrestore(&pending_queue_lock, flags);
+    return;
+  }
+  list_del(&blk_request->queue);
+  spin_unlock_irqrestore(&pending_queue_lock, flags);
+
+  spin_lock_irqsave(&io_done_queue_lock, flags);
+  list_add_tail(&blk_request->queue, &io_done_queue);
+  spin_unlock_irqrestore(&io_done_queue_lock, flags);
+
+  /* enqueue work */
+  cpu_mask = mark_hyp_event(blk_request->domain, _HYP_EVENT_BLK_RX);
+
+  return;
+}
+
+/*
+ * flush_blk_queue
+ *
+ * Called by the hypervisor synchronously when there is something to do
+ * (block transfers have completed)
+ */
+
+void flush_blk_queue(void)
+{
+  blk_request_t *blk_request;
+  int position = 0;
+  blk_ring_t *blk_ring;
+  unsigned long flags;
+  int loop;
+
+#if 0
+  printk("{F}"); 
+#endif
+  /*
+  if (XEN_BLK_DEBUG)  printk(XEN_BLK_DEBUG_LEVEL
+                            "XEN flush_blk_queue\n");
+  */
+
+  clear_bit(_HYP_EVENT_BLK_RX, &current->hyp_events);
+
+  /* NEED LOCK? */
+  spin_lock_irqsave(&io_done_queue_lock, flags);
+  while (!list_empty(&io_done_queue))
+  {
+    blk_request = list_entry(io_done_queue.next, blk_request_t, queue);
+    list_del (&blk_request->queue);
+    spin_unlock_irqrestore(&io_done_queue_lock, flags);
+
+    /* place on ring for guest os */ 
+    blk_ring = blk_request->domain->blk_ring_base;
+    position = blk_ring->rx_prod;
+
+    if (XEN_BLK_DEBUG)  printk(XEN_BLK_DEBUG_LEVEL
+                              "XEN flush_blk_queue [%d]\n", position);
+
+    memcpy(&blk_ring->rx_ring[position], &blk_request->request,
+          sizeof(blk_ring_entry_t));
+    blk_ring->rx_prod = BLK_RX_RING_INC(blk_ring->rx_prod);
+
+    /* notify appropriate guest os */
+    set_bit(_EVENT_BLK_RX,
+           &blk_request->domain->shared_info->events);
+
+    if (0)
+    {
+      int temp;
+      struct buffer_head *bh = blk_request->bh;
+      char * vbuffer = bh->b_data;
+
+      printk (KERN_ALERT "XEN return block 0x%lx\n", bh->b_blocknr);
+
+      for (temp = 0; temp < bh->b_size; temp++)
+      {
+       if (temp % 16 == 0)       printk ("[%04x]  ", temp);
+       else if (temp % 4 == 0)   printk (" ");
+                                 printk ("%02x",
+                                         vbuffer[temp] & 255);
+       if ((temp + 1) % 16 == 0) printk ("\n");
+      }
+      printk ("\n\n");
+    }
+
+    /* free the buffer header allocated in do_block_io_op */
+    if (blk_request->bh)
+    {
+      kfree(blk_request->bh);                     /* alloc in do_block_io_op */
+    }
+
+    spin_lock_irqsave(&free_queue_lock, flags);
+    list_add_tail(&blk_request->queue, &free_queue);
+    spin_unlock_irqrestore(&free_queue_lock, flags);
+
+    spin_lock_irqsave(&io_done_queue_lock, flags);
+  }
+  spin_unlock_irqrestore(&io_done_queue_lock, flags);
+
+  /*
+   * now check if there is any pending work from any domain
+   * that we were previously unable to process.
+   *
+   * NOTE: the current algorithm will check _every_ domain
+   * and wake up _every_ domain that has pending work.
+   * In the future, we should stop waking up domains once
+   * there isn't any space for their requests any more
+   * ALSO, we need to maintain a counter of the last domain
+   * that we woke up for fairness... we shouldn't restart
+   * at domain 0 every time (although we might want to special
+   * case domain 0);
+   */
+  for (loop = 0; loop < XEN_BLOCK_MAX_DOMAINS; loop++)
+  {
+    int domain = pending_work & (1 << loop);
+
+    if (domain)
+    {
+      struct task_struct *mytask = current;
+
+      /*
+      printk (KERN_ALERT 
+             "flush_blk_queue  pending_work: %x  domain: %d  loop: %d\n",
+             pending_work, domain, loop);
+      */
+      /* IS THERE A BETTER WAY OF FINDING THE TASK STRUCT FOR A 
+       * PARTICULAR DOMAIN? 
+       *
+       * WHAT IF THE TASK GOES AWAY BEFORE WE HAVE A CHANCE TO
+       * FINISH PROCESSING ALL OF ITS REQUESTS?
+       */
+      while (mytask->domain != loop)
+      {
+       mytask = mytask->next_task;
+      }
+      do_block_io_op_domain(mytask);
+
+      pending_work = pending_work & !(1 << loop);
+      /*
+      printk (KERN_ALERT 
+             "                 pending_work: %x  domain: %d  loop: %d\n",
+             pending_work, domain, loop);
+      */
+    }
+  }
+}
+
+/*
+ * do_block_io_op
+ *
+ * Accept a block io request from a guest operating system.
+ * There is an entry in the hypervisor_call_table (xen/arch/i386/entry.S).
+ */
+
+long do_block_io_op (void)
+{
+  return do_block_io_op_domain(current);
+}
+
+/*
+ * do_block_io_op
+ *
+ * handle the requests for a particular domain
+ */
+
+long do_block_io_op_domain (struct task_struct* task)
+{
+  blk_ring_t *blk_ring = task->blk_ring_base;
+  int loop;
+
+#if 0
+  printk("{%d}", current->domain); 
+#endif
+  if (XEN_BLK_DEBUG)  printk(XEN_BLK_DEBUG_LEVEL
+                            "XEN do_block_io_op %d %d\n",
+                            blk_ring->tx_cons, blk_ring->tx_prod);
+
+  for (loop = blk_ring->tx_cons;
+       loop != blk_ring->tx_prod;
+       loop = BLK_TX_RING_INC(loop))
+  {
+    int status = 1;
+
+    switch (blk_ring->tx_ring[loop].operation)
+    {
+      case XEN_BLOCK_READ :
+      case XEN_BLOCK_WRITE :
+      {
+       status = dispatch_rw_block_io(loop);
+       break;
+      }
+      case XEN_BLOCK_PROBE :
+      {
+       status = dispatch_probe_block_io(loop);
+       break;
+      }
+      case XEN_BLOCK_DEBUG :
+      {
+       status = dispatch_debug_block_io(loop);
+       break;
+      }
+      default :
+      {
+       printk (KERN_ALERT "error: unknown block io operation [%d]\n",
+               blk_ring->tx_ring[loop].operation);
+       BUG();
+      }
+    }
+
+    if (status)
+    {
+      /* unable to successfully issue / complete command, maybe because
+       * another resource (e.g. disk request buffers) is unavailable.
+       * stop removing items from the communications ring and try 
+       * again later 
+       */
+
+      /*
+      printk ("do_block_io_op_domain  domain:%d, pending_work: %x\n",
+             task->domain, pending_work);
+      */
+      pending_work = pending_work | (1 << task->domain);
+      /*
+      printk ("do_block_io_op_domain  domain:%d, pending_work: %x\n",
+             task->domain, pending_work);
+      */
+      break;
+    }
+  }
+
+  blk_ring->tx_cons = loop;
+
+  return 0L;
+}
+
+int dispatch_debug_block_io (int index)
+{
+  struct task_struct *task;
+  blk_ring_t *blk_ring = current->blk_ring_base;
+  char * buffer;
+  char output[1000];
+
+  int foobar = (unsigned long)blk_ring->tx_ring[index].block_number;
+
+  printk (KERN_ALERT "dispatch_debug_block_io %d\n", foobar);
+
+  buffer = phys_to_virt(blk_ring->tx_ring[index].buffer);
+  strcpy (buffer, "DEBUG\n");
+
+  task = current;
+  sprintf (buffer, "current %d\n", current->domain);
+  sprintf (buffer, "%s  tx: prod: %d, cons: %d, size: %d\n", buffer,
+          blk_ring->tx_prod, blk_ring->tx_cons, blk_ring->tx_ring_size);
+  sprintf (buffer, "%s  rx: prod: %d, cons: %d, size: %d\n", buffer,
+          blk_ring->rx_prod, blk_ring->rx_cons, blk_ring->rx_ring_size);
+
+  task = task->next_task;
+  while (task != current)
+  {
+    blk_ring = task->blk_ring_base;
+    sprintf (buffer, "%stask %d\n", buffer, task->domain);
+    if (blk_ring != NULL)
+    {
+      sprintf (buffer, "%s  tx: prod: %d, cons: %d, size: %d\n",
+              buffer, blk_ring->tx_prod, blk_ring->tx_cons, 
+              blk_ring->tx_ring_size);
+      sprintf (buffer, "%s  rx: prod: %d, cons: %d, size: %d\n",
+              buffer, blk_ring->rx_prod, blk_ring->rx_cons, 
+              blk_ring->rx_ring_size);
+    }
+    task = task->next_task;
+  }
+  dumpx(output, foobar);
+  sprintf (buffer, "%s%s\n", buffer, output);
+
+  return 0;
+}
+
+int dispatch_probe_block_io (int index)
+{
+  blk_ring_t *blk_ring = current->blk_ring_base;
+  xen_disk_info_t *xdi;
+
+  xdi = phys_to_virt(blk_ring->tx_ring[index].buffer);
+
+  ide_probe_devices(xdi);
+
+  return 0;
+}
+
+int dispatch_rw_block_io (int index)
+{
+  blk_ring_t *blk_ring = current->blk_ring_base;
+  struct buffer_head *bh;
+  struct request_queue *rq;
+  int operation;
+  blk_request_t *blk_request;
+  unsigned long flags;
+
+    /*
+     * check to make sure that the block request seems at least
+     * a bit legitimate
+     */
+    if ((blk_ring->tx_ring[index].block_size & (0x200 - 1)) != 0)
+    {
+      printk(KERN_ALERT
+            "    error: dodgy block size: %d\n", 
+            blk_ring->tx_ring[index].block_size);
+      BUG();
+    }
+
+    if (XEN_BLK_DEBUG) 
+    {
+    printk(XEN_BLK_DEBUG_LEVEL
+          "    tx_cons: %d  tx_prod %d  index: %d     op: %s, pri: %s\n",
+          blk_ring->tx_cons, blk_ring->tx_prod, index,
+          (blk_ring->tx_ring[index].operation == XEN_BLOCK_READ ? "read" : "write"),
+          (blk_ring->tx_ring[index].priority == XEN_BLOCK_SYNC ? "sync" : "async"));
+    }
+
+    {
+      char temp[100];
+      sprintf(temp, "issue  buf: 0x%p, bh: 0x%p, blkno: 0x%lx",
+             blk_ring->tx_ring[index].buffer, bh,
+             (unsigned long)blk_ring->tx_ring[index].block_number);
+      printx(temp);
+    }
+
+    /* find an empty request slot */
+    spin_lock_irqsave(&free_queue_lock, flags);
+    if (list_empty(&free_queue))
+    {
+      /*      printk (KERN_ALERT "dispatch_rw_block_io EMPTY FREE LIST!! %d\n", index); */
+      spin_unlock_irqrestore(&free_queue_lock, flags);
+      return 1;
+    }
+    blk_request = list_entry(free_queue.next, blk_request_t, queue);
+    list_del(&blk_request->queue);
+    spin_unlock_irqrestore(&free_queue_lock, flags);
+
+    /* place request on pending list */
+    spin_lock_irqsave(&pending_queue_lock, flags);
+    list_add_tail(&blk_request->queue, &pending_queue);
+    spin_unlock_irqrestore(&pending_queue_lock, flags);
+
+    /* we'll be doing this frequently, would a cache be appropriate? */
+    /* free in flush_blk_queue */
+    bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), 
+                                       GFP_KERNEL);
+    if (!bh)
+    {
+      printk(KERN_ALERT "ERROR: bh is null\n");
+      BUG();
+    }
+
+    /* set just the important bits of the buffer header */
+    memset (bh, 0, sizeof (struct buffer_head));
+
+    bh->b_blocknr = blk_ring->tx_ring[index].block_number;   /* block number */
+    bh->b_size = blk_ring->tx_ring[index].block_size;          /* block size */
+    bh->b_dev = blk_ring->tx_ring[index].device;   /* device (B_FREE = free) */
+    bh->b_rsector = blk_ring->tx_ring[index].sector_number; /* sector number */
+                                                    
+    bh->b_data = phys_to_virt(blk_ring->tx_ring[index].buffer);
+                                                          /* ptr to data blk */
+    bh->b_count.counter = 1;                       /* users using this block */
+    bh->b_xen_request = (void *)blk_request;           /* save block request */
+    
+
+    if (blk_ring->tx_ring[index].operation == XEN_BLOCK_WRITE)
+    {
+      bh->b_state = ((1 << BH_JBD) |                  /* buffer state bitmap */
+                    (1 << BH_Mapped) |
+                    (1 << BH_Req) |
+                    (1 << BH_Dirty) |
+                    (1 << BH_Uptodate));
+      operation = WRITE;
+    }
+    else
+    {
+      bh->b_state = (1 << BH_Mapped);                 /* buffer state bitmap */
+      operation = READ;
+    }
+
+    /* save meta data about request */
+    memcpy(&blk_request->request,                    /* NEED COPY_FROM_USER? */
+          &blk_ring->tx_ring[index], sizeof(blk_ring_entry_t));
+    blk_request->bh = bh;
+    blk_request->domain = current;                    /* save current domain */
+
+    /* dispatch single block request */
+    ll_rw_block(operation, 1, &bh);                        /* linux top half */
+    rq = blk_get_queue(bh->b_rdev);                         
+    generic_unplug_device(rq);                          /* linux bottom half */
+
+    return 0;
+}
+
+/*
+ * initialize_block_io
+ *
+ * initialize everything for block io 
+ * called from arch/i386/setup.c::start_of_day
+ */
+
+void initialize_block_io ()
+{
+  int loop;
+
+  INIT_LIST_HEAD(&free_queue);
+  INIT_LIST_HEAD(&pending_queue);
+  INIT_LIST_HEAD(&io_done_queue);
+  
+  spin_lock_init(&free_queue_lock);
+  spin_lock_init(&pending_queue_lock);
+  spin_lock_init(&io_done_queue_lock);
+
+  for (loop = 0; loop < XEN_BLK_REQUEST_LIST_SIZE; loop++)
+  {
+    list_add_tail(&blk_request_list[loop].queue, &free_queue);
+  }
+
+  /*
+   * if bit i is true then domain i has work for us to do.
+   */
+  pending_work = 0;
+
+  return;
+}
+
+
+#ifdef DEBUG
+
+/*
+ * debug dump_queue
+ * arguments: queue head, name of queue
+ */
+void dump_queue(struct list_head *queue, char *name)
+{
+  struct list_head *list;
+  int loop = 0;
+
+  printk ("QUEUE %s %lx   n: %lx, p: %lx\n", name,  (unsigned long)queue,
+         (unsigned long) queue->next, (unsigned long) queue->prev);
+  list_for_each (list, queue)
+  {
+    printk ("  %s %d : %lx   n: %lx, p: %lx\n", name, loop++, 
+           (unsigned long)list,
+           (unsigned long)list->next, (unsigned long)list->prev);
+  }
+}
+
+void dump_queue_head(struct list_head *queue, char *name)
+{
+  struct list_head *list;
+  int loop = 0;
+
+  printk ("QUEUE %s %lx   n: %lx, p: %lx\n", name,  (unsigned long)queue,
+         (unsigned long) queue->next, (unsigned long) queue->prev);
+  list_for_each (list, queue)
+  {
+    printk ("      %d : %lx   n: %lx, p: %lx\n", loop++, 
+           (unsigned long)list,
+           (unsigned long)list->next, (unsigned long)list->prev);
+    if (loop >= 5) return;
+  }
+}
+
+#endif /* DEBUG */
+
+
+#define debug_block_size 200000
+#define debug_output_size 10
+
+static int    countx = 0;
+static char * arrayx[debug_block_size];
+static int    outputx = 0;
+
+void
+printx (char * string)
+{
+  char * s;
+
+  s = (char *) kmalloc(strlen(string), GFP_KERNEL);
+  strcpy (s, string);
+  arrayx[countx++] = s;
+
+  if (countx >= debug_block_size)
+  {
+    countx = 0;
+    printk (KERN_ALERT "printx wrap\n");
+  }
+
+}
+
+void
+dumpx (char *buffer, int count)
+{
+  int loop;
+  int start;
+
+  sprintf (buffer, "debug dump\n");
+
+  /*
+  for (loop = outputx;
+       loop < outputx + debug_output_size && loop < countx; 
+       loop ++)
+  {
+    sprintf (buffer, "%s%02d:%s\n", buffer, loop, arrayx[loop]);
+  }
+  outputx = loop;
+  */
+  
+  if (count == 0 || count > countx)
+  {
+    start = 0;
+  }
+  else
+  {
+    start = countx - count;
+  }
+
+  printk (KERN_ALERT "DUMPX BUFFER\n");
+  for (loop = start; loop < countx; loop++)
+  {
+    printk (KERN_ALERT "%4d %s\n", loop, arrayx[loop]);
+  }
+  printk (KERN_ALERT "DUMPX bye bye\n");
+}
+
diff --git a/xen-2.4.16/drivers/char/Makefile b/xen-2.4.16/drivers/char/Makefile
new file mode 100644 (file)
index 0000000..574b7d2
--- /dev/null
@@ -0,0 +1,8 @@
+
+include $(BASEDIR)/Rules.mk
+
+default: $(OBJS)
+       $(LD) -r -o driver.o $(OBJS)
+
+clean:
+       rm -f *.o *~ core
diff --git a/xen-2.4.16/drivers/char/xen_kbd.c b/xen-2.4.16/drivers/char/xen_kbd.c
new file mode 100644 (file)
index 0000000..a1f7cea
--- /dev/null
@@ -0,0 +1,113 @@
+#include <asm-i386/io.h>
+
+#define KEYBOARD_IRQ 1
+
+#define KBD_STATUS_REG      0x64 /* Status register (R) */
+#define KBD_CNTL_REG        0x64 /* Controller command register (W) */
+#define KBD_DATA_REG        0x60 /* Keyboard data register (R/W) */
+
+/* register status bits */
+#define KBD_STAT_OBF        0x01 /* Keyboard output buffer full */
+#define KBD_STAT_IBF        0x02 /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST    0x04 /* Self test successful */
+#define KBD_STAT_CMD        0x08 /* Last write was a command write (0=data) */
+
+#define KBD_STAT_UNLOCKED    0x10 /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF   0x20 /* Mouse output buffer full */
+#define KBD_STAT_GTO        0x40 /* General receive/xmit timeout */
+#define KBD_STAT_PERR       0x80 /* Parity error */
+
+#define kbd_read_input() inb(KBD_DATA_REG)
+#define kbd_read_status() inb(KBD_STATUS_REG)
+
+
+static void
+dispatch_scancode (unsigned char scancode)
+{
+    /*
+     * we could be a bit more clever here, but why?
+     * just add a jump to your debug routine for the appropriate character.
+     */
+    switch (scancode)
+    {
+    case 0x01 :                                                       /* esc */
+       printk ("<esc>");
+       break;
+    case 0x9e :                                                         /* a */
+       printk ("a");
+       break;
+    case 0x9f :                                                         /* s */
+       printk ("s");
+       break;
+    case 0xae :                                                         /* c */
+       printk ("c");
+       break;
+    case 0xb0 :                                                         /* b */
+       printk ("b");
+       break;
+    case 0xbb :                                                        /* f1 */
+       printk ("<f1>");
+       break;
+    case 0xbc :                                                        /* f2 */
+       printk ("<f2>");
+       break;
+    case 0xbd :                                                        /* f3 */
+       printk ("<f3>");
+       break;
+    case 0xbe :                                                        /* f4 */
+       printk ("<f4>");
+       break;
+    case 0xbf :                                                        /* f5 */
+       /* xen_block_dump_state(); */
+       break;
+    default :
+       /* printk ("%x ", scancode); */
+    }
+
+    return; 
+}
+
+
+/* regs should be struct pt_regs */
+
+static void keyboard_interrupt(int irq, void *dev_id, void *regs)
+{
+    unsigned char status = kbd_read_status();
+    unsigned int work = 10000;
+    
+    while ((--work > 0) && (status & KBD_STAT_OBF))
+    {
+       unsigned char scancode;
+       
+       scancode = kbd_read_input();
+       
+       if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
+       {
+           if (status & KBD_STAT_MOUSE_OBF)
+               /* mouse event, ignore */;
+           else
+               dispatch_scancode (scancode);
+       }
+       status = kbd_read_status();
+    }
+    
+    if (!work)
+       printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status);
+    
+    return;
+}
+
+
+extern int request_irq(unsigned int, 
+                      void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long, const char *, void *);
+
+
+void initialize_keyboard()
+{
+    if(!request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL))
+       printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ); 
+
+    return; 
+}
+
diff --git a/xen-2.4.16/drivers/char/xen_serial.c b/xen-2.4.16/drivers/char/xen_serial.c
new file mode 100644 (file)
index 0000000..9a290ad
--- /dev/null
@@ -0,0 +1,93 @@
+#include <asm-i386/io.h>
+
+/* Register offsets */
+#define NS16550_RBR    0x00    /* receive buffer       */
+#define NS16550_THR    0x00    /* transmit holding     */
+#define NS16550_IER    0x01    /* interrupt enable     */
+#define NS16550_IIR    0x02    /* interrupt identity   */
+#define NS16550_FCR     0x02    /* FIFO control         */
+#define NS16550_LCR    0x03    /* line control         */
+#define NS16550_MCR    0x04    /* MODEM control        */
+#define NS16550_LSR    0x05    /* line status          */
+#define NS16550_MSR    0x06    /* MODEM status         */
+#define NS16550_SCR    0x07    /* scratch              */
+#define NS16550_DDL    0x00    /* divisor latch (ls) ( DLAB=1) */
+#define NS16550_DLM    0x01    /* divisor latch (ms) ( DLAB=1) */
+
+/* Interrupt enable register */
+#define NS16550_IER_ERDAI      0x01    /* rx data recv'd       */
+#define NS16550_IER_ETHREI     0x02    /* tx reg. empty        */
+#define NS16550_IER_ELSI       0x04    /* rx line status       */
+#define NS16550_IER_EMSI       0x08    /* MODEM status         */
+
+/* FIFO control register */
+#define NS16550_FCR_ENABLE      0x01    /* enable FIFO          */
+#define NS16550_FCR_CLRX        0x02    /* clear Rx FIFO        */
+#define NS16550_FCR_CLTX        0x04    /* clear Tx FIFO        */
+#define NS16550_FCR_DMA         0x10    /* enter DMA mode       */
+#define NS16550_FCR_TRG1        0x00    /* Rx FIFO trig lev 1   */
+#define NS16550_FCR_TRG4        0x40    /* Rx FIFO trig lev 4   */
+#define NS16550_FCR_TRG8        0x80    /* Rx FIFO trig lev 8   */
+#define NS16550_FCR_TRG14       0xc0    /* Rx FIFO trig lev 14  */
+
+/* MODEM control register */
+#define NS16550_MCR_DTR        0x01    /* Data Terminal Ready  */
+#define NS16550_MCR_RTS        0x02    /* Request to Send      */
+#define NS16550_MCR_OUT1        0x04    /* OUT1: unused         */
+#define NS16550_MCR_OUT2        0x08    /* OUT2: interrupt mask */
+#define NS16550_MCR_LOOP       0x10    /* Loop                 */
+
+#define SERIAL_BASE 0x3f8  /* XXX SMH: horrible hardwired COM1   */
+#define SERAIL_ECHO 0      /* XXX SMH: set to 1 for 'echo' on rx */
+
+
+
+static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+    int c; 
+
+    /* XXX SMH: should probably check this is an RX interrupt :-) */
+
+    /* clear the interrupt by reading the character */
+    c = inb(SERIAL_BASE + NS16550_RBR );
+
+    if (c==0x04) {
+       /* This is 'debug me please' => just dump info and halt machine */
+       printk("serial_rx_int: got EOT => halting machine.\n"); 
+       printk("<not actually halting for now>\n"); 
+    }
+
+#ifdef SERIAL_ECHO
+    printk("%c", c); 
+#endif
+
+    return; 
+}
+
+
+extern int request_irq(unsigned int, 
+                      void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long, const char *, void *);
+
+
+void initialize_serial() 
+{
+    int fifo = 1;  /* must be a ns16550a at least, surely? */
+
+    if(fifo) {
+       /* Clear FIFOs, enable, trigger at 1 byte */
+       outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
+            NS16550_FCR_CLRX  | NS16550_FCR_CLTX, SERIAL_BASE+NS16550_FCR);
+    }
+
+    outb(NS16550_MCR_OUT2, SERIAL_BASE + NS16550_MCR);   /* Modem control */
+    outb(NS16550_IER_ERDAI, SERIAL_BASE + NS16550_IER ); /* Setup interrupts */
+
+    /* XXX SMH: this is a hack; probably is IRQ4 but grab both anyway */
+    if(!request_irq(4, serial_rx_int, 0, "serial", 0x1234))
+       printk("initialize_serial: failed to get IRQ4 :-(\n"); 
+    if(!request_irq(3, serial_rx_int, 0, "serial", 0x5678))
+       printk("initialize_serial: failed to get IRQ3 :-(\n"); 
+    
+    return; 
+}
diff --git a/xen-2.4.16/drivers/ide/ide-disk.c.orig b/xen-2.4.16/drivers/ide/ide-disk.c.orig
new file mode 100644 (file)
index 0000000..984e53c
--- /dev/null
@@ -0,0 +1,1550 @@
+/*
+ *  linux/drivers/ide/ide-disk.c       Version 1.10    June 9, 2000
+ *
+ *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
+ */
+
+/*
+ *  Mostly written by Mark Lord <mlord@pobox.com>
+ *                and Gadi Oxman <gadio@netvision.net.il>
+ *                and Andre Hedrick <andre@linux-ide.org>
+ *
+ * This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
+ *
+ * Version 1.00                move disk only code from ide.c to ide-disk.c
+ *                     support optional byte-swapping of all data
+ * Version 1.01                fix previous byte-swapping code
+ * Version 1.02                remove ", LBA" from drive identification msgs
+ * Version 1.03                fix display of id->buf_size for big-endian
+ * Version 1.04                add /proc configurable settings and S.M.A.R.T support
+ * Version 1.05                add capacity support for ATA3 >= 8GB
+ * Version 1.06                get boot-up messages to show full cyl count
+ * Version 1.07                disable door-locking if it fails
+ * Version 1.08                fixed CHS/LBA translations for ATA4 > 8GB,
+ *                     process of adding new ATA4 compliance.
+ *                     fixed problems in allowing fdisk to see
+ *                     the entire disk.
+ * Version 1.09                added increment of rq->sector in ide_multwrite
+ *                     added UDMA 3/4 reporting
+ * Version 1.10                request queue changes, Ultra DMA 100
+ * Version 1.11                added 48-bit lba
+ * Version 1.12                adding taskfile io access method
+ */
+
+#define IDEDISK_VERSION        "1.12"
+
+#undef REALLY_SLOW_IO          /* most systems can safely undef this */
+
+#include <xeno/config.h>
+#include <xeno/module.h>
+#include <xeno/types.h>
+#include <xeno/lib.h>
+#include <xeno/timer.h>
+#include <xeno/mm.h>
+#include <xeno/interrupt.h>
+#include <xeno/major.h>
+#include <xeno/errno.h>
+#include <xeno/genhd.h>
+#include <xeno/slab.h>
+#include <xeno/delay.h>
+#include <xeno/ide.h>
+
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+#else
+#define IS_PDC4030_DRIVE (0)   /* auto-NULLs out pdc4030 code */
+#endif
+
+#ifdef CONFIG_IDE_TASKFILE_IO
+#  undef __TASKFILE__IO /* define __TASKFILE__IO */
+#else /* CONFIG_IDE_TASKFILE_IO */
+#  undef __TASKFILE__IO
+#endif /* CONFIG_IDE_TASKFILE_IO */
+
+#ifndef __TASKFILE__IO
+
+static void idedisk_bswap_data (void *buffer, int wcount)
+{
+       u16 *p = buffer;
+
+       while (wcount--) {
+               *p = *p << 8 | *p >> 8; p++;
+               *p = *p << 8 | *p >> 8; p++;
+       }
+}
+
+static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+       ide_input_data(drive, buffer, wcount);
+       if (drive->bswap)
+               idedisk_bswap_data(buffer, wcount);
+}
+
+static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+       if (drive->bswap) {
+               idedisk_bswap_data(buffer, wcount);
+               ide_output_data(drive, buffer, wcount);
+               idedisk_bswap_data(buffer, wcount);
+       } else
+               ide_output_data(drive, buffer, wcount);
+}
+
+#endif /* __TASKFILE__IO */
+
+/*
+ * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
+ * value for this drive (from its reported identification information).
+ *
+ * Returns:    1 if lba_capacity looks sensible
+ *             0 otherwise
+ *
+ * It is called only once for each drive.
+ */
+static int lba_capacity_is_ok (struct hd_driveid *id)
+{
+       unsigned long lba_sects, chs_sects, head, tail;
+
+       if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+               printk("48-bit Drive: %llu \n", id->lba_capacity_2);
+               return 1;
+       }
+
+       /*
+        * The ATA spec tells large drives to return
+        * C/H/S = 16383/16/63 independent of their size.
+        * Some drives can be jumpered to use 15 heads instead of 16.
+        * Some drives can be jumpered to use 4092 cyls instead of 16383.
+        */
+       if ((id->cyls == 16383
+            || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
+           id->sectors == 63 &&
+           (id->heads == 15 || id->heads == 16) &&
+           id->lba_capacity >= 16383*63*id->heads)
+               return 1;
+
+       lba_sects   = id->lba_capacity;
+       chs_sects   = id->cyls * id->heads * id->sectors;
+
+       /* perform a rough sanity check on lba_sects:  within 10% is OK */
+       if ((lba_sects - chs_sects) < chs_sects/10)
+               return 1;
+
+       /* some drives have the word order reversed */
+       head = ((lba_sects >> 16) & 0xffff);
+       tail = (lba_sects & 0xffff);
+       lba_sects = (head | (tail << 16));
+       if ((lba_sects - chs_sects) < chs_sects/10) {
+               id->lba_capacity = lba_sects;
+               return 1;       /* lba_capacity is (now) good */
+       }
+
+       return 0;       /* lba_capacity value may be bad */
+}
+
+#ifndef __TASKFILE__IO
+
+/*
+ * read_intr() is the handler for disk read/multread interrupts
+ */
+static ide_startstop_t read_intr (ide_drive_t *drive)
+{
+       byte stat;
+       int i;
+       unsigned int msect, nsect;
+       struct request *rq;
+
+       /* new way for dealing with premature shared PCI interrupts */
+       if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
+               if (stat & (ERR_STAT|DRQ_STAT)) {
+                       return ide_error(drive, "read_intr", stat);
+               }
+               /* no data yet, so wait for another interrupt */
+               ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+               return ide_started;
+       }
+       msect = drive->mult_count;
+       
+read_next:
+       rq = HWGROUP(drive)->rq;
+       if (msect) {
+               if ((nsect = rq->current_nr_sectors) > msect)
+                       nsect = msect;
+               msect -= nsect;
+       } else
+               nsect = 1;
+       idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
+#ifdef DEBUG
+       printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
+               drive->name, rq->sector, rq->sector+nsect-1,
+               (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
+#endif
+       rq->sector += nsect;
+       rq->buffer += nsect<<9;
+       rq->errors = 0;
+       i = (rq->nr_sectors -= nsect);
+       if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
+               ide_end_request(1, HWGROUP(drive));
+       if (i > 0) {
+               if (msect)
+                       goto read_next;
+               ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+                return ide_started;
+       }
+        return ide_stopped;
+}
+
+/*
+ * write_intr() is the handler for disk write interrupts
+ */
+static ide_startstop_t write_intr (ide_drive_t *drive)
+{
+       byte stat;
+       int i;
+       ide_hwgroup_t *hwgroup = HWGROUP(drive);
+       struct request *rq = hwgroup->rq;
+
+       if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+               printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", drive->name, rq->nr_sectors, stat);
+        } else {
+#ifdef DEBUG
+               printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
+                       drive->name, rq->sector, (unsigned long) rq->buffer,
+                       rq->nr_sectors-1);
+#endif
+               if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) {
+                       rq->sector++;
+                       rq->buffer += 512;
+                       rq->errors = 0;
+                       i = --rq->nr_sectors;
+                       --rq->current_nr_sectors;
+                       if (((long)rq->current_nr_sectors) <= 0)
+                               ide_end_request(1, hwgroup);
+                       if (i > 0) {
+                               idedisk_output_data (drive, rq->buffer, SECTOR_WORDS);
+                               ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+                                return ide_started;
+                       }
+                        return ide_stopped;
+               }
+               return ide_stopped;     /* the original code did this here (?) */
+       }
+       return ide_error(drive, "write_intr", stat);
+}
+
+/*
+ * ide_multwrite() transfers a block of up to mcount sectors of data
+ * to a drive as part of a disk multiple-sector write operation.
+ *
+ * Returns 0 on success.
+ *
+ * Note that we may be called from two contexts - the do_rw_disk context
+ * and IRQ context. The IRQ can happen any time after we've output the
+ * full "mcount" number of sectors, so we must make sure we update the
+ * state _before_ we output the final part of the data!
+ */
+int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
+{
+       ide_hwgroup_t   *hwgroup= HWGROUP(drive);
+       struct request  *rq = &hwgroup->wrq;
+       do {
+               char *buffer;
+               int nsect = rq->current_nr_sectors;
+               if (nsect > mcount)
+                       nsect = mcount;
+               mcount -= nsect;
+               buffer = rq->buffer;
+
+               rq->sector += nsect;
+               rq->buffer += nsect << 9;
+               rq->nr_sectors -= nsect;
+               rq->current_nr_sectors -= nsect;
+
+               /* Do we move to the next bh after this? */
+               if (!rq->current_nr_sectors) {
+                       struct buffer_head *bh = rq->bh->b_reqnext;
+
+                       /* end early early we ran out of requests */
+                       if (!bh) {
+                               mcount = 0;
+                       } else {
+                               rq->bh = bh;
+                               rq->current_nr_sectors = bh->b_size >> 9;
+                               rq->buffer             = bh->b_data;
+                       }
+               }
+
+               /*
+                * Ok, we're all setup for the interrupt
+                * re-entering us on the last transfer.
+                */
+               idedisk_output_data(drive, buffer, nsect<<7);
+       } while (mcount);
+
+        return 0;
+}
+
+/*
+ * multwrite_intr() is the handler for disk multwrite interrupts
+ */
+static ide_startstop_t multwrite_intr (ide_drive_t *drive)
+{
+       byte stat;
+       int i;
+       ide_hwgroup_t *hwgroup = HWGROUP(drive);
+       struct request *rq = &hwgroup->wrq;
+
+       if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+               if (stat & DRQ_STAT) {
+                       /*
+                        *      The drive wants data. Remember rq is the copy
+                        *      of the request
+                        */
+                       if (rq->nr_sectors) {
+                               if (ide_multwrite(drive, drive->mult_count))
+                                       return ide_stopped;
+                               ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+                               return ide_started;
+                       }
+               } else {
+                       /*
+                        *      If the copy has all the blocks completed then
+                        *      we can end the original request.
+                        */
+                       if (!rq->nr_sectors) {  /* all done? */
+                               rq = hwgroup->rq;
+                               for (i = rq->nr_sectors; i > 0;){
+                                       i -= rq->current_nr_sectors;
+                                       ide_end_request(1, hwgroup);
+                               }
+                               return ide_stopped;
+                       }
+               }
+               return ide_stopped;     /* the original code did this here (?) */
+       }
+       return ide_error(drive, "multwrite_intr", stat);
+}
+#endif /* __TASKFILE__IO */
+
+#ifdef __TASKFILE__IO
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block);
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block);
+
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+       if (rq->cmd == READ)
+               goto good_command;
+       if (rq->cmd == WRITE)
+               goto good_command;
+
+       printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+       ide_end_request(0, HWGROUP(drive));
+       return ide_stopped;
+
+good_command:
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+       if (IS_PDC4030_DRIVE) {
+               extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+               return promise_rw_disk(drive, rq, block);
+       }
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+       if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))  /* 48-bit LBA */
+               return lba_48_rw_disk(drive, rq, (unsigned long long) block);
+       if (drive->select.b.lba)                /* 28-bit LBA */
+               return lba_28_rw_disk(drive, rq, (unsigned long) block);
+
+       /* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+       return chs_rw_disk(drive, rq, (unsigned long) block);
+}
+
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+       int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+
+#if 1
+       lba48bit = drive->addressing;
+#endif
+
+       if ((cmd == READ) && (drive->using_dma))
+               return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+       else if ((cmd == READ) && (drive->mult_count))
+               return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+       else if (cmd == READ)
+               return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+       else if ((cmd == WRITE) && (drive->using_dma))
+               return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+       else if ((cmd == WRITE) && (drive->mult_count))
+               return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+       else if (cmd == WRITE)
+               return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+       else
+               return WIN_NOP;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+       struct hd_drive_task_hdr        taskfile;
+       struct hd_drive_hob_hdr         hobfile;
+       ide_task_t                      args;
+
+       task_ioreg_t command    = get_command(drive, rq->cmd);
+       unsigned int track      = (block / drive->sect);
+       unsigned int sect       = (block % drive->sect) + 1;
+       unsigned int head       = (track % drive->head);
+       unsigned int cyl        = (track / drive->head);
+
+       memset(&taskfile, 0, sizeof(task_struct_t));
+       memset(&hobfile, 0, sizeof(hob_struct_t));
+
+       taskfile.sector_count   = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+       taskfile.sector_number  = sect;
+       taskfile.low_cylinder   = cyl;
+       taskfile.high_cylinder  = (cyl>>8);
+       taskfile.device_head    = head;
+       taskfile.device_head    |= drive->select.all;
+       taskfile.command        = command;
+
+#ifdef DEBUG
+       printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+       if (lba)        printk("LBAsect=%lld, ", block);
+       else            printk("CHS=%d/%d/%d, ", cyl, head, sect);
+       printk("sectors=%ld, ", rq->nr_sectors);
+       printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+       memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+       memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+       args.command_type       = ide_cmd_type_parser(&args);
+       args.prehandler         = ide_pre_handler_parser(&taskfile, &hobfile);
+       args.handler            = ide_handler_parser(&taskfile, &hobfile);
+       args.posthandler        = NULL;
+       args.rq                 = (struct request *) rq;
+       args.block              = block;
+       rq->special             = NULL;
+       rq->special             = (ide_task_t *)&args;
+
+       return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+       struct hd_drive_task_hdr        taskfile;
+       struct hd_drive_hob_hdr         hobfile;
+       ide_task_t                      args;
+
+       task_ioreg_t command    = get_command(drive, rq->cmd);
+
+       memset(&taskfile, 0, sizeof(task_struct_t));
+       memset(&hobfile, 0, sizeof(hob_struct_t));
+
+       taskfile.sector_count   = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+       taskfile.sector_number  = block;
+       taskfile.low_cylinder   = (block>>=8);
+       taskfile.high_cylinder  = (block>>=8);
+       taskfile.device_head    = ((block>>8)&0x0f);
+       taskfile.device_head    |= drive->select.all;
+       taskfile.command        = command;
+
+
+#ifdef DEBUG
+       printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+       if (lba)        printk("LBAsect=%lld, ", block);
+       else            printk("CHS=%d/%d/%d, ", cyl, head, sect);
+       printk("sectors=%ld, ", rq->nr_sectors);
+       printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+       memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+       memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+       args.command_type       = ide_cmd_type_parser(&args);
+       args.prehandler         = ide_pre_handler_parser(&taskfile, &hobfile);
+       args.handler            = ide_handler_parser(&taskfile, &hobfile);
+       args.posthandler        = NULL;
+       args.rq                 = (struct request *) rq;
+       args.block              = block;
+       rq->special             = NULL;
+       rq->special             = (ide_task_t *)&args;
+
+       return do_rw_taskfile(drive, &args);
+}
+
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+       struct hd_drive_task_hdr        taskfile;
+       struct hd_drive_hob_hdr         hobfile;
+       ide_task_t                      args;
+
+       task_ioreg_t command    = get_command(drive, rq->cmd);
+
+       memset(&taskfile, 0, sizeof(task_struct_t));
+       memset(&hobfile, 0, sizeof(hob_struct_t));
+
+       taskfile.sector_count   = rq->nr_sectors;
+       hobfile.sector_count    = (rq->nr_sectors>>8);
+
+       if (rq->nr_sectors == 65536) {
+               taskfile.sector_count   = 0x00;
+               hobfile.sector_count    = 0x00;
+       }
+
+       taskfile.sector_number  = block;        /* low lba */
+       taskfile.low_cylinder   = (block>>=8);  /* mid lba */
+       taskfile.high_cylinder  = (block>>=8);  /* hi  lba */
+       hobfile.sector_number   = (block>>=8);  /* low lba */
+       hobfile.low_cylinder    = (block>>=8);  /* mid lba */
+       hobfile.high_cylinder   = (block>>=8);  /* hi  lba */
+       taskfile.device_head    = drive->select.all;
+       hobfile.device_head     = taskfile.device_head;
+       hobfile.control         = (drive->ctl|0x80);
+       taskfile.command        = command;
+
+#ifdef DEBUG
+       printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
+       if (lba)        printk("LBAsect=%lld, ", block);
+       else            printk("CHS=%d/%d/%d, ", cyl, head, sect);
+       printk("sectors=%ld, ", rq->nr_sectors);
+       printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+       memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
+       memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+       args.command_type       = ide_cmd_type_parser(&args);
+       args.prehandler         = ide_pre_handler_parser(&taskfile, &hobfile);
+       args.handler            = ide_handler_parser(&taskfile, &hobfile);
+       args.posthandler        = NULL;
+       args.rq                 = (struct request *) rq;
+       args.block              = block;
+       rq->special             = NULL;
+       rq->special             = (ide_task_t *)&args;
+
+       return do_rw_taskfile(drive, &args);
+}
+
+#else /* !__TASKFILE__IO */
+/*
+ * do_rw_disk() issues READ and WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors.
+ * It also takes care of issuing special DRIVE_CMDs.
+ */
+static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+       if (IDE_CONTROL_REG)
+               OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+
+#ifdef CONFIG_BLK_DEV_PDC4030
+       if (drive->select.b.lba || IS_PDC4030_DRIVE) {
+#else /* !CONFIG_BLK_DEV_PDC4030 */
+       if (drive->select.b.lba) {
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+
+               if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+                       task_ioreg_t tasklets[10];
+
+                       tasklets[0] = 0;
+                       tasklets[1] = 0;
+                       tasklets[2] = rq->nr_sectors;
+                       tasklets[3] = (rq->nr_sectors>>8);
+                       if (rq->nr_sectors == 65536) {
+                               tasklets[2] = 0x00;
+                               tasklets[3] = 0x00;
+                       }
+                       tasklets[4] = (task_ioreg_t) block;
+                       tasklets[5] = (task_ioreg_t) (block>>8);
+                       tasklets[6] = (task_ioreg_t) (block>>16);
+                       tasklets[7] = (task_ioreg_t) (block>>24);
+                       tasklets[8] = (task_ioreg_t) 0;
+                       tasklets[9] = (task_ioreg_t) 0;
+//                     tasklets[8] = (task_ioreg_t) (block>>32);
+//                     tasklets[9] = (task_ioreg_t) (block>>40);
+#ifdef DEBUG
+                       printk("%s: %sing: LBAsect=%lu, sectors=%ld, buffer=0x%08lx, LBAsect=0x%012lx\n",
+                               drive->name,
+                               (rq->cmd==READ)?"read":"writ",
+                               block,
+                               rq->nr_sectors,
+                               (unsigned long) rq->buffer,
+                               block);
+                       printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n",
+                               drive->name, tasklets[3], tasklets[2],
+                               tasklets[9], tasklets[8], tasklets[7],
+                               tasklets[6], tasklets[5], tasklets[4]);
+#endif
+                       OUT_BYTE(tasklets[1], IDE_FEATURE_REG);
+                       OUT_BYTE(tasklets[3], IDE_NSECTOR_REG);
+                       OUT_BYTE(tasklets[7], IDE_SECTOR_REG);
+                       OUT_BYTE(tasklets[8], IDE_LCYL_REG);
+                       OUT_BYTE(tasklets[9], IDE_HCYL_REG);
+
+                       OUT_BYTE(tasklets[0], IDE_FEATURE_REG);
+                       OUT_BYTE(tasklets[2], IDE_NSECTOR_REG);
+                       OUT_BYTE(tasklets[4], IDE_SECTOR_REG);
+                       OUT_BYTE(tasklets[5], IDE_LCYL_REG);
+                       OUT_BYTE(tasklets[6], IDE_HCYL_REG);
+                       OUT_BYTE(0x00|drive->select.all,IDE_SELECT_REG);
+               } else {
+#ifdef DEBUG
+                       printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
+                               drive->name, (rq->cmd==READ)?"read":"writ",
+                               block, rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+                       OUT_BYTE(0x00, IDE_FEATURE_REG);
+                       OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
+                       OUT_BYTE(block,IDE_SECTOR_REG);
+                       OUT_BYTE(block>>=8,IDE_LCYL_REG);
+                       OUT_BYTE(block>>=8,IDE_HCYL_REG);
+                       OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
+               }
+       } else {
+               unsigned int sect,head,cyl,track;
+               track = block / drive->sect;
+               sect  = block % drive->sect + 1;
+               OUT_BYTE(sect,IDE_SECTOR_REG);
+               head  = track % drive->head;
+               cyl   = track / drive->head;
+
+               OUT_BYTE(0x00, IDE_FEATURE_REG);
+               OUT_BYTE((rq->nr_sectors==256)?0x00:rq->nr_sectors,IDE_NSECTOR_REG);
+               OUT_BYTE(cyl,IDE_LCYL_REG);
+               OUT_BYTE(cyl>>8,IDE_HCYL_REG);
+               OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
+#ifdef DEBUG
+               printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
+                       drive->name, (rq->cmd==READ)?"read":"writ", cyl,
+                       head, sect, rq->nr_sectors, (unsigned long) rq->buffer);
+#endif
+       }
+#ifdef CONFIG_BLK_DEV_PDC4030
+       if (IS_PDC4030_DRIVE) {
+               extern ide_startstop_t do_pdc4030_io(ide_drive_t *, struct request *);
+               return do_pdc4030_io (drive, rq);
+       }
+#endif /* CONFIG_BLK_DEV_PDC4030 */
+       if (rq->cmd == READ) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+               if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+                       return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
+               if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+                       OUT_BYTE(drive->mult_count ? WIN_MULTREAD_EXT : WIN_READ_EXT, IDE_COMMAND_REG);
+               } else {
+                       OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
+               }
+               return ide_started;
+       }
+       if (rq->cmd == WRITE) {
+               ide_startstop_t startstop;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+               if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+                       return ide_started;
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+               if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
+                       OUT_BYTE(drive->mult_count ? WIN_MULTWRITE_EXT : WIN_WRITE_EXT, IDE_COMMAND_REG);
+               } else {
+                       OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
+               }
+               if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+                       printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name,
+                               drive->mult_count ? "MULTWRITE" : "WRITE");
+                       return startstop;
+               }
+               if (!drive->unmask)
+                       __cli();        /* local CPU only */
+               if (drive->mult_count) {
+                       ide_hwgroup_t *hwgroup = HWGROUP(drive);
+       /*
+        * Ugh.. this part looks ugly because we MUST set up
+        * the interrupt handler before outputting the first block
+        * of data to be written.  If we hit an error (corrupted buffer list)
+        * in ide_multwrite(), then we need to remove the handler/timer
+        * before returning.  Fortunately, this NEVER happens (right?).
+        *
+        * Except when you get an error it seems...
+        */
+                       hwgroup->wrq = *rq; /* scratchpad */
+                       ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
+                       if (ide_multwrite(drive, drive->mult_count)) {
+                               unsigned long flags;
+                               spin_lock_irqsave(&io_request_lock, flags);
+                               hwgroup->handler = NULL;
+                               del_timer(&hwgroup->timer);
+                               spin_unlock_irqrestore(&io_request_lock, flags);
+                               return ide_stopped;
+                       }
+               } else {
+                       ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+                       idedisk_output_data(drive, rq->buffer, SECTOR_WORDS);
+               }
+               return ide_started;
+       }
+       printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+       ide_end_request(0, HWGROUP(drive));
+       return ide_stopped;
+}
+
+#endif /* __TASKFILE__IO */
+
+static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+       MOD_INC_USE_COUNT;
+       if (drive->removable && drive->usage == 1) {
+               struct hd_drive_task_hdr taskfile;
+               struct hd_drive_hob_hdr hobfile;
+               memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+               memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+               taskfile.command = WIN_DOORLOCK;
+               check_disk_change(inode->i_rdev);
+               /*
+                * Ignore the return code from door_lock,
+                * since the open() has already succeeded,
+                * and the door_lock is irrelevant at this point.
+                */
+               if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+                       drive->doorlocking = 0;
+       }
+       return 0;
+}
+
+static int do_idedisk_flushcache(ide_drive_t *drive);
+
+static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
+{
+       if (drive->removable && !drive->usage) {
+               struct hd_drive_task_hdr taskfile;
+               struct hd_drive_hob_hdr hobfile;
+               memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+               memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+               taskfile.command = WIN_DOORUNLOCK;
+               invalidate_bdev(inode->i_bdev, 0);
+               if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+                       drive->doorlocking = 0;
+       }
+       if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+               if (do_idedisk_flushcache(drive))
+                       printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+                               drive->name);
+       MOD_DEC_USE_COUNT;
+}
+
+static int idedisk_media_change (ide_drive_t *drive)
+{
+       return drive->removable;        /* if removable, always assume it was changed */
+}
+
+static void idedisk_revalidate (ide_drive_t *drive)
+{
+       grok_partitions(HWIF(drive)->gd, drive->select.b.unit,
+                       1<<PARTN_BITS,
+                       current_capacity(drive));
+}
+
+/*
+ * Queries for true maximum capacity of the drive.
+ * Returns maximum LBA address (> 0) of the drive, 0 if failed.
+ */
+static unsigned long idedisk_read_native_max_address(ide_drive_t *drive)
+{
+       ide_task_t args;
+       unsigned long addr = 0;
+
+       if (!(drive->id->command_set_1 & 0x0400) &&
+           !(drive->id->cfs_enable_2 & 0x0100))
+               return addr;
+
+       /* Create IDE/ATA command request structure */
+       memset(&args, 0, sizeof(ide_task_t));
+       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_READ_NATIVE_MAX;
+       args.handler                            = task_no_data_intr;
+
+       /* submit command request */
+       ide_raw_taskfile(drive, &args, NULL);
+
+       /* if OK, compute maximum address value */
+       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+               addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+                    | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+                    | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+                    | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+       }
+       addr++; /* since the return value is (maxlba - 1), we add 1 */
+       return addr;
+}
+
+static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive)
+{
+       ide_task_t args;
+       unsigned long long addr = 0;
+
+       /* Create IDE/ATA command request structure */
+       memset(&args, 0, sizeof(ide_task_t));
+
+       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_READ_NATIVE_MAX_EXT;
+       args.handler                            = task_no_data_intr;
+
+        /* submit command request */
+        ide_raw_taskfile(drive, &args, NULL);
+
+       /* if OK, compute maximum address value */
+       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+               u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+                          ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+                           (args.hobRegister[IDE_SECTOR_OFFSET_HOB]); 
+               u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+                          ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+                           (args.tfRegister[IDE_SECTOR_OFFSET]);
+               addr = ((__u64)high << 24) | low;
+       }
+       addr++; /* since the return value is (maxlba - 1), we add 1 */
+       return addr;
+}
+
+#ifdef CONFIG_IDEDISK_STROKE
+/*
+ * Sets maximum virtual LBA address of the drive.
+ * Returns new maximum virtual LBA address (> 0) or 0 on failure.
+ */
+static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req)
+{
+       ide_task_t args;
+       unsigned long addr_set = 0;
+       
+       addr_req--;
+       /* Create IDE/ATA command request structure */
+       memset(&args, 0, sizeof(ide_task_t));
+       args.tfRegister[IDE_SECTOR_OFFSET]      = ((addr_req >>  0) & 0xff);
+       args.tfRegister[IDE_LCYL_OFFSET]        = ((addr_req >>  8) & 0xff);
+       args.tfRegister[IDE_HCYL_OFFSET]        = ((addr_req >> 16) & 0xff);
+       args.tfRegister[IDE_SELECT_OFFSET]      = ((addr_req >> 24) & 0x0f) | 0x40;
+       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SET_MAX;
+       args.handler                            = task_no_data_intr;
+       /* submit command request */
+       ide_raw_taskfile(drive, &args, NULL);
+       /* if OK, read new maximum address value */
+       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+               addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
+                        | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
+                        | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
+                        | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+       }
+       addr_set++;
+       return addr_set;
+}
+
+static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req)
+{
+       ide_task_t args;
+       unsigned long long addr_set = 0;
+
+       addr_req--;
+       /* Create IDE/ATA command request structure */
+       memset(&args, 0, sizeof(ide_task_t));
+       args.tfRegister[IDE_SECTOR_OFFSET]      = ((addr_req >>  0) & 0xff);
+       args.tfRegister[IDE_LCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
+       args.tfRegister[IDE_HCYL_OFFSET]        = ((addr_req >>= 8) & 0xff);
+       args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
+       args.tfRegister[IDE_COMMAND_OFFSET]     = WIN_SET_MAX_EXT;
+       args.hobRegister[IDE_SECTOR_OFFSET_HOB] = ((addr_req >>= 8) & 0xff);
+       args.hobRegister[IDE_LCYL_OFFSET_HOB]   = ((addr_req >>= 8) & 0xff);
+       args.hobRegister[IDE_HCYL_OFFSET_HOB]   = ((addr_req >>= 8) & 0xff);
+       args.hobRegister[IDE_SELECT_OFFSET_HOB] = 0x40;
+       args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+        args.handler                           = task_no_data_intr;
+       /* submit command request */
+       ide_raw_taskfile(drive, &args, NULL);
+       /* if OK, compute maximum address value */
+       if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
+               u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
+                          ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
+                           (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
+               u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
+                          ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
+                           (args.tfRegister[IDE_SECTOR_OFFSET]);
+               addr_set = ((__u64)high << 24) | low;
+       }
+       return addr_set;
+}
+
+/*
+ * Tests if the drive supports Host Protected Area feature.
+ * Returns true if supported, false otherwise.
+ */
+static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
+{
+       int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
+       printk("%s: host protected area => %d\n", drive->name, flag);
+       return flag;
+}
+
+#endif /* CONFIG_IDEDISK_STROKE */
+
+/*
+ * Compute drive->capacity, the full capacity of the drive
+ * Called with drive->id != NULL.
+ *
+ * To compute capacity, this uses either of
+ *
+ *    1. CHS value set by user       (whatever user sets will be trusted)
+ *    2. LBA value from target drive (require new ATA feature)
+ *    3. LBA value from system BIOS  (new one is OK, old one may break)
+ *    4. CHS value from system BIOS  (traditional style)
+ *
+ * in above order (i.e., if value of higher priority is available,
+ * reset will be ignored).
+ */
+static void init_idedisk_capacity (ide_drive_t  *drive)
+{
+       struct hd_driveid *id = drive->id;
+       unsigned long capacity = drive->cyl * drive->head * drive->sect;
+       unsigned long set_max = idedisk_read_native_max_address(drive);
+       unsigned long long capacity_2 = capacity;
+       unsigned long long set_max_ext;
+
+       drive->capacity48 = 0;
+       drive->select.b.lba = 0;
+
+       if (id->cfs_enable_2 & 0x0400) {
+               capacity_2 = id->lba_capacity_2;
+               drive->head             = drive->bios_head = 255;
+               drive->sect             = drive->bios_sect = 63;
+               drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
+               drive->select.b.lba     = 1;
+               set_max_ext = idedisk_read_native_max_address_ext(drive);
+               if (set_max_ext > capacity_2) {
+#ifdef CONFIG_IDEDISK_STROKE
+                       set_max_ext = idedisk_read_native_max_address_ext(drive);
+                       set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext);
+                       if (set_max_ext) {
+                               drive->capacity48 = capacity_2 = set_max_ext;
+                               drive->cyl = (unsigned int) set_max_ext / (drive->head * drive->sect);
+                               drive->select.b.lba = 1;
+                               drive->id->lba_capacity_2 = capacity_2;
+                        }
+#else /* !CONFIG_IDEDISK_STROKE */
+                       printk("%s: setmax_ext LBA %llu, native  %llu\n",
+                               drive->name, set_max_ext, capacity_2);
+#endif /* CONFIG_IDEDISK_STROKE */
+               }
+               drive->bios_cyl         = drive->cyl;
+               drive->capacity48       = capacity_2;
+               drive->capacity         = (unsigned long) capacity_2;
+               return;
+       /* Determine capacity, and use LBA if the drive properly supports it */
+       } else if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+               capacity = id->lba_capacity;
+               drive->cyl = capacity / (drive->head * drive->sect);
+               drive->select.b.lba = 1;
+       }
+
+       if (set_max > capacity) {
+#ifdef CONFIG_IDEDISK_STROKE
+               set_max = idedisk_read_native_max_address(drive);
+               set_max = idedisk_set_max_address(drive, set_max);
+               if (set_max) {
+                       drive->capacity = capacity = set_max;
+                       drive->cyl = set_max / (drive->head * drive->sect);
+                       drive->select.b.lba = 1;
+                       drive->id->lba_capacity = capacity;
+               }
+#else /* !CONFIG_IDEDISK_STROKE */
+               printk("%s: setmax LBA %lu, native  %lu\n",
+                       drive->name, set_max, capacity);
+#endif /* CONFIG_IDEDISK_STROKE */
+       }
+
+       drive->capacity = capacity;
+
+       if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
+                drive->capacity48 = id->lba_capacity_2;
+               drive->head = 255;
+               drive->sect = 63;
+               drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
+       }
+}
+
+static unsigned long idedisk_capacity (ide_drive_t *drive)
+{
+       if (drive->id->cfs_enable_2 & 0x0400)
+               return (drive->capacity48 - drive->sect0);
+       return (drive->capacity - drive->sect0);
+}
+
+static ide_startstop_t idedisk_special (ide_drive_t *drive)
+{
+       special_t *s = &drive->special;
+
+       if (s->b.set_geometry) {
+               struct hd_drive_task_hdr taskfile;
+               struct hd_drive_hob_hdr hobfile;
+               ide_handler_t *handler = NULL;
+
+               memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+               memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+               s->b.set_geometry       = 0;
+               taskfile.sector_number  = drive->sect;
+               taskfile.low_cylinder   = drive->cyl;
+               taskfile.high_cylinder  = drive->cyl>>8;
+               taskfile.device_head    = ((drive->head-1)|drive->select.all)&0xBF;
+               if (!IS_PDC4030_DRIVE) {
+                       taskfile.sector_count   = drive->sect;
+                       taskfile.command        = WIN_SPECIFY;
+                       handler                 = ide_handler_parser(&taskfile, &hobfile);
+               }
+               do_taskfile(drive, &taskfile, &hobfile, handler);
+       } else if (s->b.recalibrate) {
+               s->b.recalibrate = 0;
+               if (!IS_PDC4030_DRIVE) {
+                       struct hd_drive_task_hdr taskfile;
+                       struct hd_drive_hob_hdr hobfile;
+                       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+                       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+                       taskfile.sector_count   = drive->sect;
+                       taskfile.command        = WIN_RESTORE;
+                       do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+               }
+       } else if (s->b.set_multmode) {
+               s->b.set_multmode = 0;
+               if (drive->id && drive->mult_req > drive->id->max_multsect)
+                       drive->mult_req = drive->id->max_multsect;
+               if (!IS_PDC4030_DRIVE) {
+                       struct hd_drive_task_hdr taskfile;
+                       struct hd_drive_hob_hdr hobfile;
+                       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+                       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+                       taskfile.sector_count   = drive->mult_req;
+                       taskfile.command        = WIN_SETMULT;
+                       do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+               }
+       } else if (s->all) {
+               int special = s->all;
+               s->all = 0;
+               printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special);
+               return ide_stopped;
+       }
+       return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
+}
+
+static void idedisk_pre_reset (ide_drive_t *drive)
+{
+       int legacy = (drive->id->cfs_enable_2 & 0x0400) ? 0 : 1;
+
+       drive->special.all = 0;
+       drive->special.b.set_geometry = legacy;
+       drive->special.b.recalibrate  = legacy;
+       if (OK_TO_RESET_CONTROLLER)
+               drive->mult_count = 0;
+       if (!drive->keep_settings && !drive->using_dma)
+               drive->mult_req = 0;
+       if (drive->mult_req != drive->mult_count)
+               drive->special.b.set_multmode = 1;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int smart_enable(ide_drive_t *drive)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.feature        = SMART_ENABLE;
+       taskfile.low_cylinder   = SMART_LCYL_PASS;
+       taskfile.high_cylinder  = SMART_HCYL_PASS;
+       taskfile.command        = WIN_SMART;
+       return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, byte *buf)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.feature        = SMART_READ_VALUES;
+       taskfile.sector_count   = 0x01;
+       taskfile.low_cylinder   = SMART_LCYL_PASS;
+       taskfile.high_cylinder  = SMART_HCYL_PASS;
+       taskfile.command        = WIN_SMART;
+       (void) smart_enable(drive);
+       return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+}
+
+static int get_smart_thresholds(ide_drive_t *drive, byte *buf)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.feature        = SMART_READ_THRESHOLDS;
+       taskfile.sector_count   = 0x01;
+       taskfile.low_cylinder   = SMART_LCYL_PASS;
+       taskfile.high_cylinder  = SMART_HCYL_PASS;
+       taskfile.command        = WIN_SMART;
+       (void) smart_enable(drive);
+       return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+}
+
+static int proc_idedisk_read_cache
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *) data;
+       char            *out = page;
+       int             len;
+
+       if (drive->id)
+               len = sprintf(out,"%i\n", drive->id->buf_size / 2);
+       else
+               len = sprintf(out,"(none)\n");
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idedisk_read_smart_thresholds
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *)data;
+       int             len = 0, i = 0;
+
+       if (!get_smart_thresholds(drive, page)) {
+               unsigned short *val = (unsigned short *) page;
+               char *out = ((char *)val) + (SECTOR_WORDS * 4);
+               page = out;
+               do {
+                       out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+                       val += 1;
+               } while (i < (SECTOR_WORDS * 2));
+               len = out - page;
+       }
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_idedisk_read_smart_values
+       (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+       ide_drive_t     *drive = (ide_drive_t *)data;
+       int             len = 0, i = 0;
+
+       if (!get_smart_values(drive, page)) {
+               unsigned short *val = (unsigned short *) page;
+               char *out = ((char *)val) + (SECTOR_WORDS * 4);
+               page = out;
+               do {
+                       out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+                       val += 1;
+               } while (i < (SECTOR_WORDS * 2));
+               len = out - page;
+       }
+       PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static ide_proc_entry_t idedisk_proc[] = {
+       { "cache",              S_IFREG|S_IRUGO,        proc_idedisk_read_cache,                NULL },
+       { "geometry",           S_IFREG|S_IRUGO,        proc_ide_read_geometry,                 NULL },
+       { "smart_values",       S_IFREG|S_IRUSR,        proc_idedisk_read_smart_values,         NULL },
+       { "smart_thresholds",   S_IFREG|S_IRUSR,        proc_idedisk_read_smart_thresholds,     NULL },
+       { NULL, 0, NULL, NULL }
+};
+
+#else
+
+#define        idedisk_proc    NULL
+
+#endif /* CONFIG_PROC_FS */
+
+static int set_multcount(ide_drive_t *drive, int arg)
+{
+#ifdef __TASKFILE__IO
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+
+       if (drive->special.b.set_multmode)
+               return -EBUSY;
+
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.sector_count   = drive->mult_req;
+       taskfile.command        = WIN_SETMULT;
+       drive->mult_req         = arg;
+       drive->special.b.set_multmode = 1;
+       ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+#else /* !__TASKFILE__IO */
+       struct request rq;
+
+       if (drive->special.b.set_multmode)
+               return -EBUSY;
+       ide_init_drive_cmd (&rq);
+       rq.cmd = IDE_DRIVE_CMD;
+       drive->mult_req = arg;
+       drive->special.b.set_multmode = 1;
+       (void) ide_do_drive_cmd (drive, &rq, ide_wait);
+#endif /* __TASKFILE__IO */
+       return (drive->mult_count == arg) ? 0 : -EIO;
+}
+
+static int set_nowerr(ide_drive_t *drive, int arg)
+{
+       if (ide_spin_wait_hwgroup(drive))
+               return -EBUSY;
+       drive->nowerr = arg;
+       drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+       spin_unlock_irq(&io_request_lock);
+       return 0;
+}
+
+static int write_cache (ide_drive_t *drive, int arg)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.feature        = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+       taskfile.command        = WIN_SETFEATURES;
+
+       if (!(drive->id->cfs_enable_2 & 0x3000))
+               return 1;
+
+       (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+       drive->wcache = arg;
+       return 0;
+}
+
+static int do_idedisk_standby (ide_drive_t *drive)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       taskfile.command        = WIN_STANDBYNOW1;
+       return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int do_idedisk_flushcache (ide_drive_t *drive)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+       if (drive->id->cfs_enable_2 & 0x2400) {
+               taskfile.command        = WIN_FLUSH_CACHE_EXT;
+       } else {
+               taskfile.command        = WIN_FLUSH_CACHE;
+       }
+       return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+}
+
+static int set_acoustic (ide_drive_t *drive, int arg)
+{
+       struct hd_drive_task_hdr taskfile;
+       struct hd_drive_hob_hdr hobfile;
+       memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+       memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
+       taskfile.feature        = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
+       taskfile.sector_count   = arg;
+
+       taskfile.command        = WIN_SETFEATURES;
+       (void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+       drive->acoustic = arg;
+       return 0;
+}
+
+static int probe_lba_addressing (ide_drive_t *drive, int arg)
+{
+       drive->addressing =  0;
+
+       if (!(drive->id->cfs_enable_2 & 0x0400))
+                return -EIO;
+
+       drive->addressing = arg;
+       return 0;
+}
+
+static int set_lba_addressing (ide_drive_t *drive, int arg)
+{
+       return (probe_lba_addressing(drive, arg));
+}
+
+static void idedisk_add_settings(ide_drive_t *drive)
+{
+       struct hd_driveid *id = drive->id;
+#if 0
+       int major = HWIF(drive)->major;
+       int minor = drive->select.b.unit << PARTN_BITS;
+#endif
+
+       ide_add_setting(drive,  "bios_cyl",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->bios_cyl,               NULL);
+       ide_add_setting(drive,  "bios_head",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      255,                            1,      1,      &drive->bios_head,              NULL);
+       ide_add_setting(drive,  "bios_sect",            SETTING_RW,                                     -1,                     -1,                     TYPE_BYTE,      0,      63,                             1,      1,      &drive->bios_sect,              NULL);
+       ide_add_setting(drive,  "address",              SETTING_RW,                                     HDIO_GET_ADDRESS,       HDIO_SET_ADDRESS,       TYPE_INTA,      0,      2,                              1,      1,      &drive->addressing,     set_lba_addressing);
+       ide_add_setting(drive,  "bswap",                SETTING_READ,                                   -1,                     -1,                     TYPE_BYTE,      0,      1,                              1,      1,      &drive->bswap,                  NULL);
+       ide_add_setting(drive,  "multcount",            id ? SETTING_RW : SETTING_READ,                 HDIO_GET_MULTCOUNT,     HDIO_SET_MULTCOUNT,     TYPE_BYTE,      0,      id ? id->max_multsect : 0,      1,      1,      &drive->mult_count,             set_multcount);
+       ide_add_setting(drive,  "nowerr",               SETTING_RW,                                     HDIO_GET_NOWERR,        HDIO_SET_NOWERR,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->nowerr,                 set_nowerr);
+#if 0
+       ide_add_setting(drive,  "breada_readahead",     SETTING_RW,                                     BLKRAGET,               BLKRASET,               TYPE_INT,       0,      255,                            1,      1,      &read_ahead[major],             NULL);
+       ide_add_setting(drive,  "file_readahead",       SETTING_RW,                                     BLKFRAGET,              BLKFRASET,              TYPE_INTA,      0,      4096,                   PAGE_SIZE,      1024,   &max_readahead[major][minor],   NULL);
+       ide_add_setting(drive,  "max_kb_per_request",   SETTING_RW,                                     BLKSECTGET,             BLKSECTSET,             TYPE_INTA,      1,      255,                            1,      1,      &max_sectors[major][minor],     NULL);
+#endif
+       ide_add_setting(drive,  "lun",                  SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      7,                              1,      1,      &drive->lun,                    NULL);
+       ide_add_setting(drive,  "wcache",               SETTING_RW,                                     HDIO_GET_WCACHE,        HDIO_SET_WCACHE,        TYPE_BYTE,      0,      1,                              1,      1,      &drive->wcache,                 write_cache);
+       ide_add_setting(drive,  "acoustic",             SETTING_RW,                                     HDIO_GET_ACOUSTIC,      HDIO_SET_ACOUSTIC,      TYPE_BYTE,      0,      254,                            1,      1,      &drive->acoustic,               set_acoustic);
+       ide_add_setting(drive,  "failures",             SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->failures,               NULL);
+       ide_add_setting(drive,  "max_failures",         SETTING_RW,                                     -1,                     -1,                     TYPE_INT,       0,      65535,                          1,      1,      &drive->max_failures,           NULL);
+}
+
+static void idedisk_setup (ide_drive_t *drive)
+{
+       int i;
+       
+       struct hd_driveid *id = drive->id;
+       unsigned long capacity;
+       
+       idedisk_add_settings(drive);
+
+       if (id == NULL)
+               return;
+
+       /*
+        * CompactFlash cards and their brethern look just like hard drives
+        * to us, but they are removable and don't have a doorlock mechanism.
+        */
+       if (drive->removable && !drive_is_flashcard(drive)) {
+               /*
+                * Removable disks (eg. SYQUEST); ignore 'WD' drives 
+                */
+               if (id->model[0] != 'W' || id->model[1] != 'D') {
+                       drive->doorlocking = 1;
+               }
+       }
+       for (i = 0; i < MAX_DRIVES; ++i) {
+               ide_hwif_t *hwif = HWIF(drive);
+
+               if (drive != &hwif->drives[i]) continue;
+#ifdef DEVFS_MUST_DIE
+               hwif->gd->de_arr[i] = drive->de;
+#endif
+               if (drive->removable)
+                       hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
+               break;
+       }
+
+       /* Extract geometry if we did not already have one for the drive */
+       if (!drive->cyl || !drive->head || !drive->sect) {
+               drive->cyl     = drive->bios_cyl  = id->cyls;
+               drive->head    = drive->bios_head = id->heads;
+               drive->sect    = drive->bios_sect = id->sectors;
+       }
+
+       /* Handle logical geometry translation by the drive */
+       if ((id->field_valid & 1) && id->cur_cyls &&
+           id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {
+               drive->cyl  = id->cur_cyls;
+               drive->head = id->cur_heads;
+               drive->sect = id->cur_sectors;
+       }
+
+       /* Use physical geometry if what we have still makes no sense */
+       if (drive->head > 16 && id->heads && id->heads <= 16) {
+               drive->cyl  = id->cyls;
+               drive->head = id->heads;
+               drive->sect = id->sectors;
+       }
+
+       /* calculate drive capacity, and select LBA if possible */
+       init_idedisk_capacity (drive);
+
+       /*
+        * if possible, give fdisk access to more of the drive,
+        * by correcting bios_cyls:
+        */
+       capacity = idedisk_capacity (drive);
+       if ((capacity >= (drive->bios_cyl * drive->bios_sect * drive->bios_head)) &&
+           (!drive->forced_geom) && drive->bios_sect && drive->bios_head)
+               drive->bios_cyl = (capacity / drive->bios_sect) / drive->bios_head;
+       printk (KERN_INFO "XEN %s: %ld sectors", drive->name, capacity);
+
+       /* Give size in megabytes (MB), not mebibytes (MiB). */
+       /* We compute the exact rounded value, avoiding overflow. */
+       printk (" (%ld MB)", (capacity - capacity/625 + 974)/1950);
+
+       /* Only print cache size when it was specified */
+       if (id->buf_size)
+               printk (" w/%dKiB Cache", id->buf_size/2);
+
+       printk(", CHS=%d/%d/%d", 
+              drive->bios_cyl, drive->bios_head, drive->bios_sect);
+#ifdef CONFIG_BLK_DEV_IDEDMA
+       if (drive->using_dma)
+               (void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+       printk("\n");
+
+       drive->mult_count = 0;
+       if (id->max_multsect) {
+#ifdef CONFIG_IDEDISK_MULTI_MODE
+               id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;
+               id->multsect_valid = id->multsect ? 1 : 0;
+               drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;
+               drive->special.b.set_multmode = drive->mult_req ? 1 : 0;
+#else  /* original, pre IDE-NFG, per request of AC */
+               drive->mult_req = INITIAL_MULT_COUNT;
+               if (drive->mult_req > id->max_multsect)
+                       drive->mult_req = id->max_multsect;
+               if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
+                       drive->special.b.set_multmode = 1;
+#endif /* CONFIG_IDEDISK_MULTI_MODE */
+       }
+       drive->no_io_32bit = id->dword_io ? 1 : 0;
+       if (drive->id->cfs_enable_2 & 0x3000)
+               write_cache(drive, (id->cfs_enable_2 & 0x3000));
+       (void) probe_lba_addressing(drive, 1);
+}
+
+static int idedisk_cleanup (ide_drive_t *drive)
+{
+       if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
+               if (do_idedisk_flushcache(drive))
+                       printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
+                               drive->name);
+       return ide_unregister_subdriver(drive);
+}
+
+int idedisk_reinit(ide_drive_t *drive);
+
+/*
+ *      IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idedisk_driver = {
+       name:                   "ide-disk",
+       version:                IDEDISK_VERSION,
+       media:                  ide_disk,
+       busy:                   0,
+       supports_dma:           1,
+       supports_dsc_overlap:   0,
+       cleanup:                idedisk_cleanup,
+       standby:                do_idedisk_standby,
+       flushcache:             do_idedisk_flushcache,
+       do_request:             do_rw_disk,
+       end_request:            NULL,
+       ioctl:                  NULL,
+       open:                   idedisk_open,
+       release:                idedisk_release,
+       media_change:           idedisk_media_change,
+       revalidate:             idedisk_revalidate,
+       pre_reset:              idedisk_pre_reset,
+       capacity:               idedisk_capacity,
+       special:                idedisk_special,
+       /*proc:                 idedisk_proc,*/
+       reinit:                 idedisk_reinit,
+       ata_prebuilder:         NULL,
+       atapi_prebuilder:       NULL,
+};
+
+int idedisk_init (void);
+static ide_module_t idedisk_module = {
+       IDE_DRIVER_MODULE,
+       idedisk_init,
+       &idedisk_driver,
+       NULL
+};
+
+MODULE_DESCRIPTION("ATA DISK Driver");
+
+int idedisk_reinit (ide_drive_t *drive)
+{
+       int failed = 0;
+
+       MOD_INC_USE_COUNT;
+
+       if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+               printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+               return 1;
+       }
+       DRIVER(drive)->busy++;
+       idedisk_setup(drive);
+       if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+               printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+               (void) idedisk_cleanup(drive);
+               DRIVER(drive)->busy--;
+               return 1;
+       }
+       DRIVER(drive)->busy--;
+       failed--;
+
+       ide_register_module(&idedisk_module);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static void __exit idedisk_exit (void)
+{
+       ide_drive_t *drive;
+       int failed = 0;
+
+       while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+               if (idedisk_cleanup (drive)) {
+                       printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+                       failed++;
+               }
+               /* We must remove proc entries defined in this module.
+                  Otherwise we oops while accessing these entries */
+#ifdef CONFIG_PROC_FS
+               if (drive->proc)
+                       ide_remove_proc_entries(drive->proc, idedisk_proc);
+#endif
+       }
+       ide_unregister_module(&idedisk_module);
+}
+
+int idedisk_init (void)
+{
+       ide_drive_t *drive;
+       int failed = 0;
+       
+       MOD_INC_USE_COUNT;
+       while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
+               if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+                       printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+                       continue;
+               }
+               DRIVER(drive)->busy++;
+               idedisk_setup(drive);
+               if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
+                       printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+                       (void) idedisk_cleanup(drive);
+                       DRIVER(drive)->busy--;
+                       continue;
+               }
+               DRIVER(drive)->busy--;
+               failed--;
+       }
+       ide_register_module(&idedisk_module);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+module_init(idedisk_init);
+module_exit(idedisk_exit);
+MODULE_LICENSE("GPL");
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c
new file mode 100644 (file)
index 0000000..0416b46
--- /dev/null
@@ -0,0 +1,827 @@
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <linux/fs.h>
+#include <linux/hdreg.h>                               /* HDIO_GETGEO, et al */
+#include <linux/blkdev.h>
+#include <linux/major.h>
+
+/* NOTE: this is drive independent, so no inclusion of ide.h */
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>                                       /* put_user() */
+
+#define MAJOR_NR XLBLK_MAJOR   /* force defns in blk.h, must preceed include */
+static int xlblk_major = XLBLK_MAJOR;
+
+#include <linux/blk.h>           /* must come after definition of MAJOR_NR!! */
+
+/* instead of including linux/ide.h to pick up the definitiong of byte
+ * (and consequently screwing up blk.h, we'll just copy the definition */
+typedef unsigned char  byte; 
+
+void xlblk_ide_register_disk(int, unsigned long);
+
+#define XLBLK_MAX 2                                        /* very arbitrary */
+#define XLBLK_MAJOR_NAME "blk"
+#define IDE_PARTN_BITS 6                           /* from ide.h::PARTN_BITS */
+#define IDE_PARTN_MASK ((1<<IDE_PARTN_BITS)-1)     /* from ide.h::PARTN_MASK */
+static int xlblk_blk_size[XLBLK_MAX];
+static int xlblk_blksize_size[XLBLK_MAX];
+static int xlblk_hardsect_size[XLBLK_MAX];
+static int xlblk_read_ahead[XLBLK_MAX];
+static int xlblk_max_sectors[XLBLK_MAX];
+
+#define XLBLK_RX_IRQ _EVENT_BLK_RX
+#define XLBLK_TX_IRQ _EVENT_BLK_TX
+
+typedef struct xlblk_device
+{
+  struct buffer_head *bh;
+  unsigned int tx_count;                  /* number of used slots in tx ring */
+} xlblk_device_t;
+
+xlblk_device_t xlblk_device;
+
+/* USE_REQUEST_QUEUE = 1  use (multiple) request queues
+ *                   = 0  don't use IO request queue 
+ */
+#define USE_REQUEST_QUEUE 1
+
+#define XLBLK_DEBUG       0
+#define XLBLK_DEBUG_IOCTL 0
+
+/* 
+ * disk management
+ */
+
+xen_disk_info_t xen_disk_info;
+
+/* some declarations */
+void hypervisor_request(void *         id,
+                       int            operation,
+                       char *         buffer,
+                       unsigned long  block_number,
+                       unsigned short block_size,
+                       kdev_t         device,
+                       int            mode);
+
+
+/* ------------------------------------------------------------------------
+ */
+
+static int xenolinux_block_open(struct inode *inode, struct file *filep)
+{
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "xenolinux_block_open\n"); }
+  return 0;
+}
+
+static int xenolinux_block_release(struct inode *inode, struct file *filep)
+{
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "xenolinux_block_release\n"); }
+  return 0;
+}
+
+static int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
+                         unsigned command, unsigned long argument)
+{
+  int minor_dev;
+
+  if (XLBLK_DEBUG_IOCTL)
+  {
+    printk (KERN_ALERT "xenolinux_block_ioctl\n"); 
+  }
+
+  /* check permissions */
+  if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+  if (!inode)                  return -EINVAL;
+  minor_dev = MINOR(inode->i_rdev);
+  if (minor_dev >= XLBLK_MAX)  return -ENODEV;
+
+  if (XLBLK_DEBUG_IOCTL)
+  {
+    printk (KERN_ALERT  
+           "   command: 0x%x, argument: 0x%lx, minor: 0x%x\n",
+           command, (long) argument, minor_dev); 
+  }
+  
+  switch (command)
+  {
+    case BLKGETSIZE :
+    {
+      if (XLBLK_DEBUG_IOCTL)
+      {
+       printk (KERN_ALERT
+               "   BLKGETSIZE: %x %lx\n", BLKGETSIZE, 
+               (long) xen_disk_info.disks[0].capacity); 
+      }
+      return put_user(xen_disk_info.disks[0].capacity, 
+                     (unsigned long *) argument);
+    }
+    case BLKRRPART :
+    {
+      if (XLBLK_DEBUG_IOCTL) {
+       printk (KERN_ALERT "   BLKRRPART: %x\n", BLKRRPART); }
+      break;
+    }
+    case BLKSSZGET :
+    {
+      if (XLBLK_DEBUG_IOCTL) {
+       printk (KERN_ALERT "   BLKSSZGET: %x 0x%x\n", BLKSSZGET,
+               xlblk_hardsect_size[minor_dev]); }
+      return xlblk_hardsect_size[minor_dev]; 
+    }
+    case HDIO_GETGEO :
+    {
+      struct hd_geometry *geo = (struct hd_geometry *)argument;
+
+      if (XLBLK_DEBUG_IOCTL) {
+       printk (KERN_ALERT "   HDIO_GETGEO: %x\n", HDIO_GETGEO); }
+
+      if (!argument) return -EINVAL;
+      /*
+      if (put_user(0x80,  (byte *)&geo->heads)) return -EFAULT;
+      if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+      if (put_user(0x20b, (unsigned short *) &geo->cylinders)) return -EFAULT;
+      */
+      if (put_user(0x00,  (unsigned long *) &geo->start)) return -EFAULT;
+      if (put_user(0xff,  (byte *)&geo->heads)) return -EFAULT;
+      if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+      if (put_user(0x106, (unsigned short *) &geo->cylinders)) return -EFAULT;
+
+      return 0;
+    }
+    case HDIO_GETGEO_BIG :
+    {
+      struct hd_big_geometry *geo = (struct hd_big_geometry *) argument;
+
+      if (XLBLK_DEBUG_IOCTL) {
+       printk (KERN_ALERT "   HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); }
+
+      if (!argument) return -EINVAL;
+      /*
+      if (put_user(0x80,  (byte *)&geo->heads))   return -EFAULT;
+      if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+      if (put_user(0x20b, (unsigned int *) &geo->cylinders)) return -EFAULT;
+      */
+      if (put_user(0x00,  (unsigned long *) &geo->start))  return -EFAULT;
+      if (put_user(0xff,  (byte *)&geo->heads))   return -EFAULT;
+      if (put_user(0x3f,  (byte *)&geo->sectors)) return -EFAULT;
+      if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT;
+
+      return 0;
+    }
+    default :
+    {
+      if (XLBLK_DEBUG_IOCTL) {
+       printk (KERN_ALERT "   eh? unknown ioctl\n"); }
+      break;
+    }
+  }
+
+  return 0;
+}
+
+static int xenolinux_block_check(kdev_t dev)
+{
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "xenolinux_block_check\n"); }
+  return 0;
+}
+
+static int xenolinux_block_revalidate(kdev_t dev)
+{
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "xenolinux_block_revalidate\n"); }
+  return 0;
+}
+
+/*
+ * hypervisor_request
+ *
+ * request block io 
+ * 
+ * id: for guest use only.
+ * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE
+ * buffer: buffer to read/write into. this should be a
+ *   virtual address in the guest os.
+ * block_number:  block to read
+ * block_size:  size of each block
+ * device:  ide/hda is 768 or 0x300
+ * mode: XEN_BLOCK_SYNC or XEN_BLOCK_ASYNC.  async requests
+ *   will queue until a sync request is issued.
+ */
+
+void hypervisor_request(void *         id,
+                       int            operation,
+                       char *         buffer,
+                       unsigned long  block_number,
+                       unsigned short block_size,
+                       kdev_t         device,
+                       int            mode)
+{
+  blk_ring_t *blk_ring = start_info.blk_ring;
+  int position;
+  void *buffer_pa, *buffer_ma; 
+  kdev_t phys_device = (kdev_t) 0;
+  unsigned long sector_number = 0;
+
+#if 0
+  printk(KERN_ALERT "[%x]", id); 
+  printk (KERN_ALERT
+         "xlblk_req: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n",
+         id, operation, buffer, block_number, block_size, device);
+#endif
+
+  /* XXX SMH: now need to convert guest virtual address to machine address */
+  buffer_pa = (void *)virt_to_phys((unsigned long)buffer); 
+  buffer_ma = (void *)phys_to_machine((unsigned long)buffer_pa); 
+
+#if 0
+  printk(KERN_ALERT "va %p => pa %p => ma %p\n", buffer, buffer_pa, buffer_ma);
+#endif
+
+  if (operation == XEN_BLOCK_PROBE)
+  {
+    phys_device = (kdev_t) 0;
+    sector_number = 0;
+  }
+  else if (operation == XEN_BLOCK_READ || operation == XEN_BLOCK_WRITE)
+  {
+    /*
+     * map logial major device to the physical device number 
+     *
+     *           XLBLK_MAJOR -> IDE0_MAJOR  (123 -> 3)
+     */
+    if (MAJOR(device) == XLBLK_MAJOR)
+    {
+      phys_device = MKDEV(IDE0_MAJOR, 0);
+    }
+    else
+    {
+      printk (KERN_ALERT
+             "error: xl_block::hypervisor_request: unknown device [0x%x]\n", 
+             device);
+      BUG();
+    }
+  
+    /*
+     * compute real buffer location on disk
+     * (from ll_rw_block.c::submit_bh)
+     */
+    {
+      int idx = 0;
+
+      struct gendisk *gd = (struct gendisk *) xen_disk_info.disks[idx].gendisk;
+      unsigned int minor = MINOR(device);
+
+      sector_number = block_number /* * block_size >> 9 */;
+
+      if (gd != NULL)                     /* if we have a partition table... */
+      {
+       sector_number += gd->part[minor & IDE_PARTN_MASK].start_sect;
+      }
+    }
+  }
+
+  /*
+   * CHECK TO SEE IF THERE IS SPACE IN THE RING
+   */
+  if (BLK_TX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons)
+  {
+    printk (KERN_ALERT "hypervisor_request: tx_cons: %d, tx_prod:%d",
+           blk_ring->tx_cons, blk_ring->tx_prod);
+  }
+
+  /* fill out a communications ring structure 
+     and then trap into the hypervisor */
+  position = blk_ring->tx_prod;
+  blk_ring->tx_ring[position].id            = id;
+  blk_ring->tx_ring[position].priority      = mode;
+  blk_ring->tx_ring[position].operation     = operation;
+  blk_ring->tx_ring[position].buffer        = buffer_ma;
+  blk_ring->tx_ring[position].block_number  = block_number;
+  blk_ring->tx_ring[position].block_size    = block_size;
+  blk_ring->tx_ring[position].device        = phys_device;
+  blk_ring->tx_ring[position].sector_number = sector_number;
+
+  blk_ring->tx_prod = BLK_TX_RING_INC(blk_ring->tx_prod);
+
+  if (mode == XEN_BLOCK_SYNC)
+  {
+    /* trap into hypervisor */
+    HYPERVISOR_block_io_op();
+  }
+  else if (mode == XEN_BLOCK_ASYNC)
+  {
+    /* for now, do nothing.  the request will go in the ring and
+       the next sync request will trigger the hypervisor to act */
+  }
+  else
+  {
+    /* ummm, unknown mode. */
+    BUG();
+  }
+
+  return;
+}
+
+
+/*
+ * do_xlblk_request
+ *
+ * read a block; request is in a request queue
+ *
+ * TO DO: should probably release the io_request_lock and then re-acquire
+ *        (see LDD p. 338)
+ */
+
+static void do_xlblk_request (request_queue_t *rq)
+{
+  struct request *req;
+
+  if (XLBLK_DEBUG)
+  {
+    printk (KERN_ALERT "xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME); 
+  }
+
+  while (!QUEUE_EMPTY)
+  {
+    struct buffer_head *bh;
+    unsigned long offset;
+    unsigned long length;
+    int rw;
+
+    req = CURRENT;
+
+    if (XLBLK_DEBUG)
+    {
+      printk (KERN_ALERT
+             "do_xlblk_request %p: cmd %i, sec %lx, (%li) bh:%p\n",
+             req, req->cmd, req->sector,
+             req->current_nr_sectors, req->bh);
+    }
+
+    /* is there space in the tx ring for this request?
+     * if the ring is full, then leave the request in the queue
+     *
+     * THIS IS A BIT BOGUS SINCE XEN COULD BE UPDATING TX_CONS
+     * AT THE SAME TIME
+     */
+    {
+      blk_ring_t *blk_ring = start_info.blk_ring;
+      
+      if (BLK_RX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons)
+      {
+       printk (KERN_ALERT "OOPS, TX LOOKS FULL  cons: %d  prod: %d\n",
+               blk_ring->tx_cons, blk_ring->tx_prod);
+       break;
+      }
+    }
+
+    req->errors = 0;
+    blkdev_dequeue_request(req);
+
+    bh = req->bh;
+
+    while (bh)
+    {
+
+    offset = bh->b_rsector << 9;
+    length = bh->b_size;
+    
+    rw = req->cmd;
+    if (rw == READA)  rw= READ;
+    if ((rw != READ) && (rw != WRITE))
+    {
+      printk (KERN_ALERT
+             "XenoLinux Virtual Block Device: bad command: %d\n", rw);
+      BUG();
+    }
+
+    /*
+    if (XLBLK_DEBUG)
+    {
+      printk (KERN_ALERT "xlblk.c::do_xlblk_request\n");
+      printk (KERN_ALERT "  b_blocknr: 0x%lx %ld\n", 
+                         bh->b_blocknr, bh->b_blocknr);
+      printk (KERN_ALERT "  b_size:    0x%x  %d\n", bh->b_size, bh->b_size);
+      printk (KERN_ALERT "  b_dev:     0x%x  %d\n", bh->b_dev, bh->b_dev);
+      printk (KERN_ALERT "  b_rsector: 0x%lx %ld\n", 
+                         bh->b_rsector, bh->b_rsector);
+    }
+    */
+
+    hypervisor_request (req, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
+                       bh->b_data, bh->b_rsector, bh->b_size, 
+                       bh->b_dev, XEN_BLOCK_SYNC);
+
+      bh = bh->b_reqnext;
+    }
+  }
+
+  return;
+}
+
+/*
+ * xenolinux_block_request
+ *
+ * read a block without using a request queue
+ */
+
+static int xenolinux_block_request(request_queue_t *rq,
+                                  int rw,
+                                  struct buffer_head *bh)
+{
+  unsigned int minor;
+  unsigned long offset;
+  unsigned long length;
+
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "xlblk.c::xenolinux_block_request: %lx %d %lx\n",
+           (unsigned long) rq, rw, (unsigned long) bh); }
+  /*
+  printk (KERN_ALERT "xlblk.c::xlblk_request: op:%d bh:%p sect:%lu sz:%u\n",
+         rw,  bh, bh->b_rsector, bh->b_size);
+  */
+
+  minor = MINOR(bh->b_rdev);
+
+  offset = bh->b_rsector << 9;
+  length = bh->b_size;
+
+  if (rw == READA)  rw= READ;
+  if ((rw != READ) && (rw != WRITE))
+  {
+    printk (KERN_ALERT 
+           "XenoLinux Virtual Block Device: bad command: %d\n", rw);
+    goto fail;
+  }
+
+  hypervisor_request (bh, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, 
+                     bh->b_data, bh->b_rsector, bh->b_size, 
+                     bh->b_dev, XEN_BLOCK_SYNC);
+
+  return 0;
+
+ fail:
+  return 0;
+}
+
+static struct block_device_operations xenolinux_block_fops = 
+{
+    open:               xenolinux_block_open,
+    release:            xenolinux_block_release,
+    ioctl:              xenolinux_block_ioctl,
+    check_media_change: xenolinux_block_check,
+    revalidate:         xenolinux_block_revalidate,
+};
+
+static void xlblk_rx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+  xlblk_device_t *dev = (xlblk_device_t *)dev_id;
+  blk_ring_t *blk_ring = start_info.blk_ring;
+  struct buffer_head *bh;
+  struct request *req;
+  int loop;
+
+  for (loop = blk_ring->rx_cons;
+       loop != blk_ring->rx_prod;
+       loop = BLK_RX_RING_INC(loop))
+  {
+    blk_ring_entry_t *bret = &blk_ring->rx_ring[loop];
+    void *buffer_pa, *buffer_va; 
+
+    buffer_pa = machine_to_phys((unsigned long)bret->buffer); 
+    buffer_va = phys_to_virt((unsigned long)buffer_pa); 
+    
+#if 0
+    printk(KERN_ALERT "xlblk_rx_int: buffer ma %p => pa %p => va %p\n", 
+          bret->buffer, buffer_pa, buffer_va); 
+
+
+    if (XLBLK_DEBUG)
+    {
+      printk (KERN_ALERT 
+             "xlblock::xlblk_rx_int [%s]\n",
+             (bret->operation == XEN_BLOCK_READ) ? "read" : "write");
+      printk (KERN_ALERT 
+             "   vbuf: %lx, pbuf: %lx, blockno: %lx, size: %x, device %x\n",
+             (unsigned long) buffer_va, (unsigned long) bret->buffer,
+             bret->block_number, bret->block_size, bret->device);
+      printk (KERN_ALERT "   bret: %p  bh: %p\n", bret, bret->id); 
+    }
+
+    /*
+    printk (KERN_ALERT
+           "xlblk_rx: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n",
+           bret->id, bret->operation, bret->buffer, bret->block_number,
+           bret->block_size, bret->device);
+    */
+#endif
+
+    if (USE_REQUEST_QUEUE)
+    {
+      req = (struct request *)bret->id;
+      printk(KERN_ALERT "|%x|", req); 
+
+      if (!end_that_request_first(req, 1, "NAME"))
+      {
+       blkdev_dequeue_request(req);
+
+       /* should be end_that_request_last(req)
+          to wake up waiting processes (with complete) */
+       blkdev_release_request(req);
+      }
+
+      /*
+       if (XLBLK_DEBUG)
+       {
+         int temp;
+         printk(KERN_ALERT 
+                "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n",
+                vbuffer, bret->block_number, bret->block_size, bret->device,
+                bh->b_end_io); 
+
+         for (temp = 0; temp < bret->block_size; temp++)
+         {
+           if (temp % 16 == 0)       printk ("[%4x]  ", temp);
+           else if (temp % 4 == 0)   printk (" ");
+                                     printk ("%02x",
+                                             vbuffer[temp] & 255);
+            if ((temp + 1) % 16 == 0) printk ("\n");
+         }
+         printk ("\n\n");
+       }
+      */
+
+#ifdef BOGUS
+      req = (struct request *)bret->id;
+      while ((bh = req->bh) != NULL)
+      {
+       req->bh = bh->b_reqnext;
+       bh->b_reqnext = NULL;
+       bh->b_end_io(bh,1);
+      }
+      blkdev_release_request(req);
+#endif /* BOGUS  */
+    }
+    else
+    {
+      bh = (struct buffer_head *)bret->id;
+      bh->b_end_io(bh,1);
+
+      /*
+       if (XLBLK_DEBUG)
+       {
+         int temp;
+#if 0
+         printk(KERN_ALERT 
+                "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n",
+                vbuffer, bret->block_number, bret->block_size, bret->device,
+                bh->b_end_io); 
+#endif
+
+         for (temp = 0; temp < bret->block_size; temp++)
+         {
+           if (temp % 16 == 0)       printk ("[%4x]  ", temp);
+           else if (temp % 4 == 0)   printk (" ");
+                                     printk ("%02x",
+                                             vbuffer[temp] & 255);
+            if ((temp + 1) % 16 == 0) printk ("\n");
+         }
+         printk ("\n\n");
+       }
+      */    
+    }
+  }
+
+  blk_ring->rx_cons = loop;
+}
+
+static void xlblk_tx_int(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+  if (XLBLK_DEBUG) {
+    printk (KERN_ALERT "--- xlblock::xlblk_tx_int\n"); }
+}
+
+int __init xlblk_init(void)
+{
+  blk_ring_t *blk_ring = start_info.blk_ring;
+  int loop, error, result;
+
+  /*
+   * initialize memory rings to communicate with hypervisor 
+   */
+
+  if ( blk_ring == NULL ) return -ENOMEM;
+
+  blk_ring->tx_prod = blk_ring->tx_cons = 0;
+  blk_ring->rx_prod = blk_ring->rx_cons = 0;
+  blk_ring->tx_ring = NULL;
+  blk_ring->rx_ring = NULL;
+
+  blk_ring->tx_ring = kmalloc(BLK_TX_RING_SIZE * sizeof(blk_ring_entry_t),
+                             GFP_KERNEL);
+  blk_ring->rx_ring = kmalloc(BLK_RX_RING_SIZE * sizeof(blk_ring_entry_t),
+                             GFP_KERNEL);
+
+  if ((blk_ring->tx_ring == NULL) ||
+      (blk_ring->rx_ring == NULL))
+  {
+    printk (KERN_ALERT 
+           "error, could not allocate ring memory for block device\n");
+    error = -ENOBUFS;
+    goto fail;
+  }
+
+  /*
+   * setup soft interrupts to communicate with hypervisor
+   */
+
+  error = request_irq(XLBLK_RX_IRQ, xlblk_rx_int, 0, "xlblk-rx", 
+                     &xlblk_device);
+  if (error)
+  {
+    printk(KERN_ALERT "Could not allocate receive interrupt\n");
+    goto fail;
+  }
+
+  error = request_irq(XLBLK_TX_IRQ, xlblk_tx_int, 0, "xlblk-tx", 
+                     &xlblk_device);
+  if (error)
+  {
+    printk(KERN_ALERT "Could not allocate transmit interrupt\n");
+    free_irq(XLBLK_RX_IRQ, &xlblk_device);
+    goto fail;
+  }
+
+  /*
+   * get information about physical drives
+   *
+   */
+  {
+    /* NOTE: this should only occur in domain 0 */
+    memset (&xen_disk_info, 0, sizeof(xen_disk_info));
+    xen_disk_info.count = 0;
+
+    hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info,
+                      0, 0, (kdev_t) 0, XEN_BLOCK_SYNC);
+
+    {
+      int loop;
+      for (loop = 0; loop < xen_disk_info.count; loop++)
+      {
+       printk (KERN_ALERT "  %2d: type: %d, capacity: %ld\n",
+               loop, xen_disk_info.disks[loop].type, 
+               xen_disk_info.disks[loop].capacity);
+      }
+    }
+  }
+
+  /*
+   * initialize device driver
+   */
+
+  SET_MODULE_OWNER(&xenolinux_block_fops);
+
+  result = register_blkdev(xlblk_major, "block", &xenolinux_block_fops);
+  if (result < 0)
+  {
+    printk (KERN_ALERT "xenolinux block: can't get major %d\n", xlblk_major);
+    return result;
+  }
+
+  /* initialize global arrays in drivers/block/ll_rw_block.c */
+  blk_size[xlblk_major] = xlblk_blk_size;
+  blksize_size[xlblk_major] = xlblk_blksize_size;
+  hardsect_size[xlblk_major] = xlblk_hardsect_size;
+  read_ahead[xlblk_major] = xlblk_read_ahead;
+  max_sectors[xlblk_major] = xlblk_max_sectors;
+  for (loop = 0; loop < XLBLK_MAX; loop++)
+  {
+    xlblk_blk_size[loop] = xen_disk_info.disks[0].capacity;
+    xlblk_blksize_size[loop] = 512;
+    xlblk_hardsect_size[loop] = 512;
+    xlblk_read_ahead[loop] = 8; 
+    xlblk_max_sectors[loop] = 128;
+  }
+
+  if (USE_REQUEST_QUEUE)
+  {
+    /* NEED TO MODIFY THIS TO HANDLE MULTIPLE QUEUES
+     * also, should replace do_xlblk_request with blk.h::DEVICE_REQUEST
+     */
+    blk_init_queue(BLK_DEFAULT_QUEUE(xlblk_major), do_xlblk_request);
+    blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0);
+  }
+  else
+  {
+    /* we don't use __make_request in ll_rw_blk */
+    blk_queue_make_request(BLK_DEFAULT_QUEUE(xlblk_major), 
+                          xenolinux_block_request);
+  }
+  xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity);
+
+  /*
+   * completion 
+   */
+  printk(KERN_ALERT 
+        "XenoLinux Virtual Block Device Driver installed [device: %d]\n",
+        xlblk_major);
+  return 0;
+
+ fail:
+  if (blk_ring->tx_ring) kfree(blk_ring->tx_ring);
+  if (blk_ring->rx_ring) kfree(blk_ring->rx_ring);
+  return error;
+}
+
+void xlblk_ide_register_disk(int idx, unsigned long capacity)
+{
+  int units;
+  int minors;
+  struct gendisk *gd;
+
+  /* plagarized from ide-probe.c::init_gendisk */
+
+  units = 2;                                       /* from ide.h::MAX_DRIVES */
+
+  minors    = units * (1<<IDE_PARTN_BITS);
+  gd        = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
+  gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+  gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+  memset(gd->part, 0, minors * sizeof(struct hd_struct));
+
+  gd->major       = xlblk_major;                  /* our major device number */
+  gd->major_name  = XLBLK_MAJOR_NAME;          /* treated special in genhd.c */
+  gd->minor_shift = IDE_PARTN_BITS;               /* num bits for partitions */
+  gd->max_p      = 1<<IDE_PARTN_BITS;         /* 1 + max partitions / drive */
+  gd->nr_real    = units;                        /* current num real drives */
+  gd->real_devices= NULL;                /* ptr to internal data (was: hwif) */
+  gd->next       = NULL;                       /* linked list of major devs */
+  gd->fops        = &xenolinux_block_fops;                /* file operations */
+  gd->de_arr      = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
+  gd->flags      = kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+  if (gd->de_arr)   memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+  if (gd->flags)    memset (gd->flags, 0, sizeof *gd->flags * units);
+  add_gendisk(gd);
+
+  xen_disk_info.disks[idx].gendisk = gd;
+
+  /* default disk size is just a big number.  in the future, we
+     need a message to probe the devices to determine the actual size */
+  register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS,
+               &xenolinux_block_fops, capacity);
+
+  return;
+}
+
+static void __exit xlblk_cleanup(void)
+{
+  /* CHANGE FOR MULTIQUEUE */
+  blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlblk_major));
+
+  /* clean up global arrays */
+  read_ahead[xlblk_major] = 0;
+  if (blk_size[xlblk_major]) kfree(blk_size[xlblk_major]);
+  blk_size[xlblk_major] = NULL;
+  if (blksize_size[xlblk_major]) kfree(blksize_size[xlblk_major]);
+  blksize_size[xlblk_major] = NULL;
+  if (hardsect_size[xlblk_major]) kfree(hardsect_size[xlblk_major]);
+  hardsect_size[xlblk_major] = NULL;
+
+  /*
+   *
+   * TODO: FOR EACH GENDISK, FREE 
+   *
+   */
+
+  if (unregister_blkdev(xlblk_major, "block"))
+  {
+    printk(KERN_ALERT
+          "XenoLinux Virtual Block Device Driver uninstalled with errors\n");
+  }
+  else
+  {
+    printk(KERN_ALERT "XenoLinux Virtual Block Device Driver uninstalled\n");
+  }
+
+  return;
+}
+
+
+#ifdef MODULE
+module_init(xlblk_init);
+module_exit(xlblk_cleanup);
+#endif
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c
new file mode 100644 (file)
index 0000000..cab6d9a
--- /dev/null
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenolinux_block_test.c
+ * 
+ */
+#define EXPORT_SYMTAB
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#include <asm/hypervisor-ifs/block.h>
+#include <asm/hypervisor-ifs/hypervisor-if.h>
+
+/******************************************************************/
+
+static struct proc_dir_entry *bdt;
+static blk_ring_entry_t meta;
+static char * data;
+
+static int proc_read_bdt(char *page, char **start, off_t off,
+                        int count, int *eof, void *data)
+{
+  switch (meta.operation)
+  {
+    case XEN_BLOCK_READ :
+    case XEN_BLOCK_WRITE :
+    {
+      return proc_dump_block(page, start, off, count, eof, data);
+    }
+    case XEN_BLOCK_DEBUG :
+    {
+      return proc_dump_debug(page, start, off, count, eof, data);
+    }
+    default :
+    {
+      printk(KERN_ALERT 
+            "block device test error: unknown operation [%c]\n",
+            meta.operation);
+      return -EINVAL;
+    }
+  }
+}
+
+int proc_dump_debug(char *page, char **start, off_t off,
+                   int count, int *eof, void *data)
+{
+  char header[100];
+  char dump[1024];
+
+  sprintf (header, "Block Device Test: Debug Dump\n\n");
+  
+  sprintf (dump, "%s\n", meta.buffer);
+  
+  if (data)
+  {
+    kfree(data);
+  }
+
+  strncpy (page, dump, count);
+  return strlen(page);
+}
+
+int proc_dump_block(char *page, char **start, off_t off,
+                   int count, int *eof, void *data)
+{
+  char header[100];
+  char dump[1024];
+  char temp[100];
+  int loop;
+
+  sprintf (header, "Block Device Test\n\n%s  blk num: %ld 0x%lx;  size: %d 0x%x;  device: 0x%x\n",
+          meta.operation == XEN_BLOCK_WRITE ? "write" : "read",
+          meta.block_number, meta.block_number,
+          meta.block_size, meta.block_size,
+          meta.device);
+  
+  sprintf (dump, "%s", header);
+
+  if (meta.buffer)
+  {
+    for (loop = 0; loop < 100; loop++)
+    {
+      int i = meta.buffer[loop];
+    
+      if (loop % 8 == 0)
+      {
+       sprintf (temp, "[%2d] ", loop);
+       strcat(dump, temp);
+      }
+      else if (loop % 2 == 0)
+      {
+       strcat(dump, " ");
+      }
+
+      sprintf (temp, " 0x%02x", i & 255);
+      strcat(dump, temp);
+      if ((loop + 1) % 8 == 0)
+      {
+       strcat(dump, "\n");
+      }
+    }
+    strcat(dump, "\n\n");
+  }
+  
+  if (data)
+  {
+    kfree(data);
+  }
+
+  strncpy (page, dump, count);
+  return strlen(page);
+}
+
+int proc_write_bdt(struct file *file, const char *buffer,
+                  unsigned long count, void *data)
+{
+  char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
+  char  opcode;
+  int  block_number = 0;
+  int  block_size = 0;
+  int  device = 0;
+  int  mode;
+
+  if (copy_from_user(local, buffer, count))
+  {
+    return -EFAULT;
+  }
+  local[count] = '\0';
+
+  sscanf(local, "%c %i %i %i", 
+        &opcode, &block_number, &block_size, &device);
+
+  if (opcode == 'r' || opcode == 'R')
+  {
+    meta.operation = XEN_BLOCK_READ;
+  }
+  else if (opcode == 'w' || opcode == 'W')
+  {
+    meta.operation = XEN_BLOCK_WRITE;
+  }
+  else if (opcode == 'd' || opcode == 'D')
+  {
+    meta.operation = XEN_BLOCK_DEBUG;
+    block_size = 10000;
+  }
+  else
+  {
+    printk(KERN_ALERT 
+          "block device test error: unknown opcode [%c]\n", opcode);
+    return -EINVAL;
+  }
+
+  if (opcode == 'r' || opcode == 'w' ||
+      opcode == 'd' || opcode == 'D')
+  {
+    mode = XEN_BLOCK_SYNC;
+  }
+  else /* (opcode == 'R' || opcode == 'W') */
+  {
+    mode = XEN_BLOCK_ASYNC;
+  }
+
+  if (data)
+  {
+    kfree(data);
+  }
+  data = kmalloc(block_size * sizeof(char), GFP_KERNEL);
+  if (data == NULL)
+  {
+    kfree(local);
+    return -ENOMEM;
+  }
+
+  meta.block_number = block_number;
+  meta.block_size   = block_size;
+  meta.device       = device;
+  meta.buffer       = data;
+
+  /* submit request */
+  hypervisor_request(0, meta.operation, meta.buffer, 
+                    meta.block_number, meta.block_size,
+                    meta.device, mode);
+
+  kfree(local);
+  return count;
+}
+                        
+
+static int __init init_module(void)
+{
+  int return_value = 0;
+
+  /* create proc entry */
+  bdt = create_proc_entry("bdt", 0644, NULL);
+  if (bdt == NULL)
+  {
+    return_value = -ENOMEM;
+    goto error;
+  }
+  bdt->data       = NULL;
+  bdt->read_proc  = proc_read_bdt;
+  bdt->write_proc = proc_write_bdt;
+  bdt->owner      = THIS_MODULE;
+
+  memset(&meta, 0, sizeof(meta));
+  
+  /* success */
+  printk(KERN_ALERT "XenoLinux Block Device Test installed\n");
+  return 0;
+
+ error:
+  return return_value;
+}
+
+static void __exit cleanup_module(void)
+{
+  if (data)
+  {
+    kfree(data);
+  }
+  printk(KERN_ALERT "XenoLinux Block Device Test uninstalled\n");
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c
new file mode 100644 (file)
index 0000000..97d4a65
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * domain 0 block driver interface
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+static int __init init_module(void)
+{
+  request_module("xl_block");
+  printk("Successfully installed domain 0 block interface\n");
+
+
+  return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+  printk("Successfully de-installed domain-0 block interface\n");
+  return 0;
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
diff --git a/xenolinux-2.4.16-sparse/drivers/block/Config.in b/xenolinux-2.4.16-sparse/drivers/block/Config.in
new file mode 100644 (file)
index 0000000..716774f
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# Block device driver configuration
+#
+mainmenu_option next_comment
+comment 'Block devices'
+
+tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD
+if [ "$CONFIG_AMIGA" = "y" ]; then
+   tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+   tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
+fi
+if [ "$CONFIG_MAC" = "y" ]; then
+   dep_bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP $CONFIG_EXPERIMENTAL
+fi
+if [ "$CONFIG_MCA" = "y" ]; then
+   tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2
+fi
+if [ "$CONFIG_ZORRO" = "y" ]; then
+   tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM
+fi
+if [ "$CONFIG_ATARI" = "y" ]; then
+   tristate 'Atari ACSI support' CONFIG_ATARI_ACSI
+   if [ "$CONFIG_ATARI_ACSI" != "n" ]; then
+      comment 'Some devices (e.g. CD jukebox) support multiple LUNs'
+      bool '  Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN
+      tristate '  Atari SLM laser printer support' CONFIG_ATARI_SLM
+   fi
+fi
+dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA
+dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT
+if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then
+   source drivers/block/paride/Config.in
+fi
+dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI
+dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI 
+dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET
+
+tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
+if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
+   int '  Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096
+fi
+dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
+
+bool 'XenoLinux virtual block device support' CONFIG_XENOLINUX_BLOCK
+
+endmenu
diff --git a/xenolinux-2.4.16-sparse/fs/partitions/check.c b/xenolinux-2.4.16-sparse/fs/partitions/check.c
new file mode 100644 (file)
index 0000000..e564544
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ *  Code extracted from drivers/block/genhd.c
+ *  Copyright (C) 1991-1998  Linus Torvalds
+ *  Re-organised Feb 1998 Russell King
+ *
+ *  We now have independent partition support from the
+ *  block drivers, which allows all the partition code to
+ *  be grouped in one location, and it to be mostly self
+ *  contained.
+ *
+ *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+#include <linux/raid/md.h>
+
+#include "check.h"
+
+#include "acorn.h"
+#include "amiga.h"
+#include "atari.h"
+#include "ldm.h"
+#include "mac.h"
+#include "msdos.h"
+#include "osf.h"
+#include "sgi.h"
+#include "sun.h"
+#include "ibm.h"
+#include "ultrix.h"
+
+extern int *blk_size[];
+
+#define CHECK_DEBUG 0
+
+int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
+
+static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
+#ifdef CONFIG_ACORN_PARTITION
+       acorn_partition,
+#endif
+#ifdef CONFIG_LDM_PARTITION
+       ldm_partition,          /* this must come before msdos */
+#endif
+#ifdef CONFIG_MSDOS_PARTITION
+       msdos_partition,
+#endif
+#ifdef CONFIG_OSF_PARTITION
+       osf_partition,
+#endif
+#ifdef CONFIG_SUN_PARTITION
+       sun_partition,
+#endif
+#ifdef CONFIG_AMIGA_PARTITION
+       amiga_partition,
+#endif
+#ifdef CONFIG_ATARI_PARTITION
+       atari_partition,
+#endif
+#ifdef CONFIG_MAC_PARTITION
+       mac_partition,
+#endif
+#ifdef CONFIG_SGI_PARTITION
+       sgi_partition,
+#endif
+#ifdef CONFIG_ULTRIX_PARTITION
+       ultrix_partition,
+#endif
+#ifdef CONFIG_IBM_PARTITION
+       ibm_partition,
+#endif
+       NULL
+};
+
+/*
+ *     This is ucking fugly but its probably the best thing for 2.4.x
+ *     Take it as a clear reminder than we should put the device name
+ *     generation in the object kdev_t points to in 2.5.
+ */
+#ifdef CONFIG_ARCH_S390
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+EXPORT_SYMBOL(genhd_dasd_name);
+#endif
+
+/*
+ * disk_name() is used by partition check code and the md driver.
+ * It formats the devicename of the indicated disk into
+ * the supplied buffer (of size at least 32), and returns
+ * a pointer to that same buffer (for convenience).
+ */
+
+char *disk_name (struct gendisk *hd, int minor, char *buf)
+{
+       const char *maj = hd->major_name;
+       unsigned int unit = (minor >> hd->minor_shift);
+       unsigned int part = (minor & ((1 << hd->minor_shift) -1 ));
+
+       if ((unit < hd->nr_real) && hd->part[minor].de) {
+               int pos;
+
+               pos = devfs_generate_path (hd->part[minor].de, buf, 64);
+               if (pos >= 0)
+                       return buf + pos;
+       }
+
+#ifdef CONFIG_ARCH_S390
+       if (genhd_dasd_name
+           && genhd_dasd_name (buf, unit, part, hd) == 0)
+               return buf;
+#endif
+       /*
+        * IDE devices use multiple major numbers, but the drives
+        * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
+        * This requires special handling here.
+        */
+       switch (hd->major) {
+               case IDE9_MAJOR:
+                       unit += 2;
+               case IDE8_MAJOR:
+                       unit += 2;
+               case IDE7_MAJOR:
+                       unit += 2;
+               case IDE6_MAJOR:
+                       unit += 2;
+               case IDE5_MAJOR:
+                       unit += 2;
+               case IDE4_MAJOR:
+                       unit += 2;
+               case IDE3_MAJOR:
+                       unit += 2;
+               case IDE2_MAJOR:
+                       unit += 2;
+               case IDE1_MAJOR:
+                       unit += 2;
+               case IDE0_MAJOR:
+                       maj = "hd";
+                       break;
+               case MD_MAJOR:
+                       sprintf(buf, "%s%d", maj, unit);
+                       return buf;
+       }
+       if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
+               unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
+               if (unit+'a' > 'z') {
+                       unit -= 26;
+                       sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
+                       if (part)
+                               sprintf(buf + 4, "%d", part);
+                       return buf;
+               }
+       }
+       if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+               int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+               if (part == 0)
+                       sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
+               else
+                       sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
+               return buf;
+       }
+       if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
+                int ctlr = hd->major - COMPAQ_CISS_MAJOR;
+                if (part == 0)
+                        sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
+                else
+                        sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
+                return buf;
+       }
+       if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
+               int ctlr = hd->major - DAC960_MAJOR;
+               if (part == 0)
+                       sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
+               else
+                       sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
+               return buf;
+       }
+       if (hd->major == ATARAID_MAJOR) {
+               int disk = minor >> hd->minor_shift;
+               int part = minor & (( 1 << hd->minor_shift) - 1);
+               if (part == 0)
+                       sprintf(buf, "%s/d%d", maj, disk);
+               else
+                       sprintf(buf, "%s/d%dp%d", maj, disk, part);
+               return buf;
+       }
+       if (part)
+               sprintf(buf, "%s%c%d", maj, unit+'a', part);
+       else
+               sprintf(buf, "%s%c", maj, unit+'a');
+       return buf;
+}
+
+/*
+ * Add a partitions details to the devices partition description.
+ */
+void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
+{
+#ifndef CONFIG_DEVFS_FS
+       char buf[40];
+#endif
+
+       hd->part[minor].start_sect = start;
+       hd->part[minor].nr_sects   = size;
+#ifdef CONFIG_DEVFS_FS
+       printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+#else
+       if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) ||
+           (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7))
+               printk(" p%d", (minor & ((1 << hd->minor_shift) - 1)));
+       else
+               printk(" %s", disk_name(hd, minor, buf));
+#endif
+}
+
+static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
+{
+       devfs_handle_t de = NULL;
+       static int first_time = 1;
+       unsigned long first_sector;
+       struct block_device *bdev;
+       char buf[64];
+       int i;
+
+  if (CHECK_DEBUG) printk (KERN_ALERT "check.c::check_partition\n");
+
+       if (first_time)
+               printk(KERN_INFO "Partition check:\n");
+       first_time = 0;
+       first_sector = hd->part[MINOR(dev)].start_sect;
+
+       /*
+        * This is a kludge to allow the partition check to be
+        * skipped for specific drives (e.g. IDE CD-ROM drives)
+        */
+       if ((int)first_sector == -1) {
+               hd->part[MINOR(dev)].start_sect = 0;
+               return;
+       }
+
+       if (hd->de_arr)
+               de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
+       i = devfs_generate_path (de, buf, sizeof buf);
+       if (i >= 0)
+               printk(KERN_INFO " /dev/%s:", buf + i);
+       else
+               printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
+       bdev = bdget(kdev_t_to_nr(dev));
+       bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+       bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
+       for (i = 0; check_part[i]; i++) {
+               int res;
+               res = check_part[i](hd, bdev, first_sector, first_part_minor);
+               if (res) {
+                       if (res < 0 &&  warn_no_part)
+                               printk(" unable to read partition table\n");
+                       goto setup_devfs;
+               }
+       }
+
+       printk(" unknown partition table\n");
+setup_devfs:
+       invalidate_bdev(bdev, 1);
+       truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
+       bdput(bdev);
+       i = first_part_minor - 1;
+       devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
+}
+
+#ifdef CONFIG_DEVFS_FS
+static void devfs_register_partition (struct gendisk *dev, int minor, int part)
+{
+       int devnum = minor >> dev->minor_shift;
+       devfs_handle_t dir;
+       unsigned int devfs_flags = DEVFS_FL_DEFAULT;
+       char devname[16];
+
+       if (dev->part[minor + part].de) return;
+       dir = devfs_get_parent (dev->part[minor].de);
+       if (!dir) return;
+       if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
+               devfs_flags |= DEVFS_FL_REMOVABLE;
+       sprintf (devname, "part%d", part);
+       dev->part[minor + part].de =
+           devfs_register (dir, devname, devfs_flags,
+                           dev->major, minor + part,
+                           S_IFBLK | S_IRUSR | S_IWUSR,
+                           dev->fops, NULL);
+}
+
+static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
+
+static void devfs_register_disc (struct gendisk *dev, int minor)
+{
+       int pos = 0;
+       int devnum = minor >> dev->minor_shift;
+       devfs_handle_t dir, slave;
+       unsigned int devfs_flags = DEVFS_FL_DEFAULT;
+       char dirname[64], symlink[16];
+       static devfs_handle_t devfs_handle;
+
+       if (dev->part[minor].de) return;
+       if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) )
+               devfs_flags |= DEVFS_FL_REMOVABLE;
+       if (dev->de_arr) {
+               dir = dev->de_arr[devnum];
+               if (!dir)  /*  Aware driver wants to block disc management  */
+                       return;
+               pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3);
+               if (pos < 0) return;
+               strncpy (dirname + pos, "../", 3);
+       }
+       else {
+               /*  Unaware driver: construct "real" directory  */
+               sprintf (dirname, "../%s/disc%d", dev->major_name, devnum);
+               dir = devfs_mk_dir (NULL, dirname + 3, NULL);
+       }
+       if (!devfs_handle)
+               devfs_handle = devfs_mk_dir (NULL, "discs", NULL);
+       dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace);
+       sprintf (symlink, "disc%d", dev->part[minor].number);
+       devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT,
+                         dirname + pos, &slave, NULL);
+       dev->part[minor].de =
+           devfs_register (dir, "disc", devfs_flags, dev->major, minor,
+                           S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
+       devfs_auto_unregister (dev->part[minor].de, slave);
+       if (!dev->de_arr)
+               devfs_auto_unregister (slave, dir);
+}
+#endif  /*  CONFIG_DEVFS_FS  */
+
+void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
+{
+#ifdef CONFIG_DEVFS_FS
+       int part;
+
+       if (!unregister)
+               devfs_register_disc (dev, minor);
+       for (part = 1; part < dev->max_p; part++) {
+               if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
+                       devfs_unregister (dev->part[part + minor].de);
+                       dev->part[part + minor].de = NULL;
+                       continue;
+               }
+               devfs_register_partition (dev, minor, part);
+       }
+       if (unregister) {
+               devfs_unregister (dev->part[minor].de);
+               dev->part[minor].de = NULL;
+               devfs_dealloc_unique_number (&disc_numspace,
+                                            dev->part[minor].number);
+       }
+#endif  /*  CONFIG_DEVFS_FS  */
+}
+
+/*
+ * This function will re-read the partition tables for a given device,
+ * and set things back up again.  There are some important caveats,
+ * however.  You must ensure that no one is using the device, and no one
+ * can start using the device while this function is being executed.
+ *
+ * Much of the cleanup from the old partition tables should have already been
+ * done
+ */
+
+void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors,
+       struct block_device_operations *ops, long size)
+{
+  if (CHECK_DEBUG)
+  {
+    if (gdev != NULL)
+    printk (KERN_ALERT 
+           "check.c::register_disk gdev:%p dev:%d min:%u ops:%p sz:%ld\n",
+           gdev, dev, minors, ops, size);
+  }
+
+       if (!gdev)
+               return;
+
+       grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size);
+}
+
+void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size)
+{
+       int i;
+       int first_minor = drive << dev->minor_shift;
+       int end_minor   = first_minor + dev->max_p;
+
+  if (CHECK_DEBUG) printk (KERN_ALERT "check.c::grok_partitions\n");
+
+       if(!dev->sizes)
+               blk_size[dev->major] = NULL;
+
+       dev->part[first_minor].nr_sects = size;
+       /* No such device or no minors to use for partitions */
+       if (!size || minors == 1)
+               return;
+
+       if (dev->sizes) {
+               dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9);
+               for (i = first_minor + 1; i < end_minor; i++)
+                       dev->sizes[i] = 0;
+       }
+       blk_size[dev->major] = dev->sizes;
+       check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor);
+
+       /*
+        * We need to set the sizes array before we will be able to access
+        * any of the partitions on this device.
+        */
+       if (dev->sizes != NULL) {       /* optional safeguard in ll_rw_blk.c */
+               for (i = first_minor; i < end_minor; i++)
+                       dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
+       }
+}
+
+unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)
+{
+       struct address_space *mapping = bdev->bd_inode->i_mapping;
+       int sect = PAGE_CACHE_SIZE / 512;
+       struct page *page;
+
+       page = read_cache_page(mapping, n/sect,
+                       (filler_t *)mapping->a_ops->readpage, NULL);
+       if (!IS_ERR(page)) {
+               wait_on_page(page);
+               if (!Page_Uptodate(page))
+                       goto fail;
+               if (PageError(page))
+                       goto fail;
+               p->v = page;
+               return (unsigned char *)page_address(page) + 512 * (n % sect);
+fail:
+               page_cache_release(page);
+       }
+       p->v = NULL;
+       return NULL;
+}
diff --git a/xenolinux-2.4.16-sparse/fs/partitions/msdos.c b/xenolinux-2.4.16-sparse/fs/partitions/msdos.c
new file mode 100644 (file)
index 0000000..34a0860
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ *  fs/partitions/msdos.c
+ *
+ *  Code extracted from drivers/block/genhd.c
+ *  Copyright (C) 1991-1998  Linus Torvalds
+ *
+ *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
+ *  in the early extended-partition checks and added DM partitions
+ *
+ *  Support for DiskManager v6.0x added by Mark Lord,
+ *  with information provided by OnTrack.  This now works for linux fdisk
+ *  and LILO, as well as loadlin and bootln.  Note that disks other than
+ *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
+ *
+ *  More flexible handling of extended partitions - aeb, 950831
+ *
+ *  Check partition table on IDE disks for common CHS translations
+ *
+ *  Re-organised Feb 1998 Russell King
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+
+#ifdef CONFIG_BLK_DEV_IDE
+#include <linux/ide.h> /* IDE xlate */
+#endif /* CONFIG_BLK_DEV_IDE */
+
+#define MSDOS_DEBUG 0
+
+#include <asm/system.h>
+
+#include "check.h"
+#include "msdos.h"
+
+#if CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
+/*
+ * Many architectures don't like unaligned accesses, which is
+ * frequently the case with the nr_sects and start_sect partition
+ * table entries.
+ */
+#include <asm/unaligned.h>
+
+#define SYS_IND(p)     (get_unaligned(&p->sys_ind))
+#define NR_SECTS(p)    ({ __typeof__(p->nr_sects) __a =        \
+                               get_unaligned(&p->nr_sects);    \
+                               le32_to_cpu(__a); \
+                       })
+
+#define START_SECT(p)  ({ __typeof__(p->start_sect) __a =      \
+                               get_unaligned(&p->start_sect);  \
+                               le32_to_cpu(__a); \
+                       })
+
+static inline int is_extended_partition(struct partition *p)
+{
+       return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
+               SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
+               SYS_IND(p) == LINUX_EXTENDED_PARTITION);
+}
+
+/*
+ * partition_name() formats the short partition name into the supplied
+ * buffer, and returns a pointer to that buffer.
+ * Used by several partition types which makes conditional inclusion messy,
+ * use __attribute__ ((unused)) instead.
+ */
+static char __attribute__ ((unused))
+       *partition_name (struct gendisk *hd, int minor, char *buf)
+{
+#ifdef CONFIG_DEVFS_FS
+       sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1)));
+       return buf;
+#else
+       return disk_name(hd, minor, buf);
+#endif
+}
+
+#define MSDOS_LABEL_MAGIC1     0x55
+#define MSDOS_LABEL_MAGIC2     0xAA
+
+static inline int
+msdos_magic_present(unsigned char *p)
+{
+       return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
+}
+
+/*
+ * Create devices for each logical partition in an extended partition.
+ * The logical partitions form a linked list, with each entry being
+ * a partition table with two entries.  The first entry
+ * is the real data partition (with a start relative to the partition
+ * table start).  The second is a pointer to the next logical partition
+ * (with a start relative to the entire extended partition).
+ * We do not create a Linux partition for the partition tables, but
+ * only for the actual data partitions.
+ */
+
+static void extended_partition(struct gendisk *hd, struct block_device *bdev,
+                       int minor, unsigned long first_size, int *current_minor)
+{
+       struct partition *p;
+       Sector sect;
+       unsigned char *data;
+       unsigned long first_sector, this_sector, this_size;
+       int mask = (1 << hd->minor_shift) - 1;
+       int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
+       int loopct = 0;         /* number of links followed
+                                  without finding a data partition */
+       int i;
+
+       this_sector = first_sector = hd->part[minor].start_sect;
+       this_size = first_size;
+
+       while (1) {
+               if (++loopct > 100)
+                       return;
+               if ((*current_minor & mask) == 0)
+                       return;
+               data = read_dev_sector(bdev, this_sector, &sect);
+               if (!data)
+                       return;
+
+               if (!msdos_magic_present(data + 510))
+                       goto done; 
+
+               p = (struct partition *) (data + 0x1be);
+
+               /*
+                * Usually, the first entry is the real data partition,
+                * the 2nd entry is the next extended partition, or empty,
+                * and the 3rd and 4th entries are unused.
+                * However, DRDOS sometimes has the extended partition as
+                * the first entry (when the data partition is empty),
+                * and OS/2 seems to use all four entries.
+                */
+
+               /* 
+                * First process the data partition(s)
+                */
+               for (i=0; i<4; i++, p++) {
+                       unsigned long offs, size, next;
+                       if (!NR_SECTS(p) || is_extended_partition(p))
+                               continue;
+
+                       /* Check the 3rd and 4th entries -
+                          these sometimes contain random garbage */
+                       offs = START_SECT(p)*sector_size;
+                       size = NR_SECTS(p)*sector_size;
+                       next = this_sector + offs;
+                       if (i >= 2) {
+                               if (offs + size > this_size)
+                                       continue;
+                               if (next < first_sector)
+                                       continue;
+                               if (next + size > first_sector + first_size)
+                                       continue;
+                       }
+
+                       add_gd_partition(hd, *current_minor, next, size);
+#if CONFIG_BLK_DEV_MD
+                       if (SYS_IND(p) == LINUX_RAID_PARTITION) {
+                           md_autodetect_dev(MKDEV(hd->major,*current_minor));
+                       }
+#endif
+
+                       (*current_minor)++;
+                       loopct = 0;
+                       if ((*current_minor & mask) == 0)
+                               goto done;
+               }
+               /*
+                * Next, process the (first) extended partition, if present.
+                * (So far, there seems to be no reason to make
+                *  extended_partition()  recursive and allow a tree
+                *  of extended partitions.)
+                * It should be a link to the next logical partition.
+                * Create a minor for this just long enough to get the next
+                * partition table.  The minor will be reused for the next
+                * data partition.
+                */
+               p -= 4;
+               for (i=0; i<4; i++, p++)
+                       if (NR_SECTS(p) && is_extended_partition(p))
+                               break;
+               if (i == 4)
+                       goto done;       /* nothing left to do */
+
+               this_sector = first_sector + START_SECT(p) * sector_size;
+               this_size = NR_SECTS(p) * sector_size;
+               minor = *current_minor;
+               put_dev_sector(sect);
+       }
+done:
+       put_dev_sector(sect);
+}
+
+/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
+   indicates linux swap.  Be careful before believing this is Solaris. */
+
+static void
+solaris_x86_partition(struct gendisk *hd, struct block_device *bdev,
+               int minor, int *current_minor)
+{
+
+#ifdef CONFIG_SOLARIS_X86_PARTITION
+       long offset = hd->part[minor].start_sect;
+       Sector sect;
+       struct solaris_x86_vtoc *v;
+       struct solaris_x86_slice *s;
+       int mask = (1 << hd->minor_shift) - 1;
+       int i;
+       char buf[40];
+
+       v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, &sect);
+       if (!v)
+               return;
+       if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
+               put_dev_sector(sect);
+               return;
+       }
+       printk(" %s: <solaris:", partition_name(hd, minor, buf));
+       if (le32_to_cpu(v->v_version) != 1) {
+               printk("  cannot handle version %d vtoc>\n",
+                       le32_to_cpu(v->v_version));
+               put_dev_sector(sect);
+               return;
+       }
+       for (i=0; i<SOLARIS_X86_NUMSLICE; i++) {
+               if ((*current_minor & mask) == 0)
+                       break;
+               s = &v->v_slice[i];
+
+               if (s->s_size == 0)
+                       continue;
+               printk(" [s%d]", i);
+               /* solaris partitions are relative to current MS-DOS
+                * one but add_gd_partition starts relative to sector
+                * zero of the disk.  Therefore, must add the offset
+                * of the current partition */
+               add_gd_partition(hd, *current_minor,
+                                le32_to_cpu(s->s_start)+offset,
+                                le32_to_cpu(s->s_size));
+               (*current_minor)++;
+       }
+       put_dev_sector(sect);
+       printk(" >\n");
+#endif
+}
+
+#ifdef CONFIG_BSD_DISKLABEL
+static void
+check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p,
+       int minor, int *current_minor)
+{
+       struct hd_struct *lin_p;
+               /* check relative position of partitions.  */
+       for (lin_p = hd->part + 1 + minor;
+            lin_p - hd->part - minor < *current_minor; lin_p++) {
+                       /* no relationship -> try again */
+               if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) ||
+                   lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size))
+                       continue;       
+                       /* equal -> no need to add */
+               if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && 
+                       lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) 
+                       return;
+                       /* bsd living within dos partition */
+               if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect 
+                       + lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) {
+#ifdef DEBUG_BSD_DISKLABEL
+                       printk("w: %d %ld+%ld,%d+%d", 
+                               lin_p - hd->part, 
+                               lin_p->start_sect, lin_p->nr_sects, 
+                               le32_to_cpu(bsd_p->p_offset),
+                               le32_to_cpu(bsd_p->p_size));
+#endif
+                       break;
+               }
+        /* ouch: bsd and linux overlap. Don't even try for that partition */
+#ifdef DEBUG_BSD_DISKLABEL
+               printk("???: %d %ld+%ld,%d+%d",
+                       lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
+                       le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size));
+#endif
+               printk("???");
+               return;
+       } /* if the bsd partition is not currently known to linux, we end
+          * up here 
+          */
+       add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset),
+                        le32_to_cpu(bsd_p->p_size));
+       (*current_minor)++;
+}
+
+/* 
+ * Create devices for BSD partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev,
+       int minor, int *current_minor, char *name, int max_partitions)
+{
+       long offset = hd->part[minor].start_sect;
+       Sector sect;
+       struct bsd_disklabel *l;
+       struct bsd_partition *p;
+       int mask = (1 << hd->minor_shift) - 1;
+       char buf[40];
+
+       l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, &sect);
+       if (!l)
+               return;
+       if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
+               put_dev_sector(sect);
+               return;
+       }
+       printk(" %s: <%s", partition_name(hd, minor, buf), name);
+
+       if (le16_to_cpu(l->d_npartitions) < max_partitions)
+               max_partitions = le16_to_cpu(l->d_npartitions);
+       for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
+               if ((*current_minor & mask) == 0)
+                       break;
+               if (p->p_fstype == BSD_FS_UNUSED) 
+                       continue;
+               check_and_add_bsd_partition(hd, p, minor, current_minor);
+       }
+       put_dev_sector(sect);
+       printk(" >\n");
+}
+#endif
+
+static void bsd_partition(struct gendisk *hd, struct block_device *bdev,
+       int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+       do_bsd_partition(hd, bdev, minor, current_minor, "bsd",
+               BSD_MAXPARTITIONS);
+#endif
+}
+
+static void netbsd_partition(struct gendisk *hd, struct block_device *bdev,
+               int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+       do_bsd_partition(hd, bdev, minor, current_minor, "netbsd",
+                       BSD_MAXPARTITIONS);
+#endif
+}
+
+static void openbsd_partition(struct gendisk *hd, struct block_device *bdev,
+               int minor, int *current_minor)
+{
+#ifdef CONFIG_BSD_DISKLABEL
+       do_bsd_partition(hd, bdev, minor, current_minor,
+                       "openbsd", OPENBSD_MAXPARTITIONS);
+#endif
+}
+
+/*
+ * Create devices for Unixware partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void unixware_partition(struct gendisk *hd, struct block_device *bdev,
+               int minor, int *current_minor)
+{
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+       long offset = hd->part[minor].start_sect;
+       Sector sect;
+       struct unixware_disklabel *l;
+       struct unixware_slice *p;
+       int mask = (1 << hd->minor_shift) - 1;
+       char buf[40];
+
+       l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, &sect);
+       if (!l)
+               return;
+       if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
+           le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
+               put_dev_sector(sect);
+               return;
+       }
+       printk(" %s: <unixware:", partition_name(hd, minor, buf));
+       p = &l->vtoc.v_slice[1];
+       /* I omit the 0th slice as it is the same as whole disk. */
+       while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
+               if ((*current_minor & mask) == 0)
+                       break;
+
+               if (p->s_label != UNIXWARE_FS_UNUSED) {
+                       add_gd_partition(hd, *current_minor, START_SECT(p),
+                                        NR_SECTS(p));
+                       (*current_minor)++;
+               }
+               p++;
+       }
+       put_dev_sector(sect);
+       printk(" >\n");
+#endif
+}
+
+/*
+ * Minix 2.0.0/2.0.2 subpartition support.
+ * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
+ * Rajeev V. Pillai    <rajeevvp@yahoo.com>
+ */
+static void minix_partition(struct gendisk *hd, struct block_device *bdev,
+               int minor, int *current_minor)
+{
+#ifdef CONFIG_MINIX_SUBPARTITION
+       long offset = hd->part[minor].start_sect;
+       Sector sect;
+       unsigned char *data;
+       struct partition *p;
+       int mask = (1 << hd->minor_shift) - 1;
+       int i;
+       char buf[40];
+
+       data = read_dev_sector(bdev, offset, &sect);
+       if (!data)
+               return;
+
+       p = (struct partition *)(data + 0x1be);
+
+       /* The first sector of a Minix partition can have either
+        * a secondary MBR describing its subpartitions, or
+        * the normal boot sector. */
+       if (msdos_magic_present (data + 510) &&
+           SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
+
+               printk(" %s: <minix:", partition_name(hd, minor, buf));
+               for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
+                       if ((*current_minor & mask) == 0)
+                               break;
+                       /* add each partition in use */
+                       if (SYS_IND(p) == MINIX_PARTITION) {
+                               add_gd_partition(hd, *current_minor,
+                                             START_SECT(p), NR_SECTS(p));
+                               (*current_minor)++;
+                       }
+               }
+               printk(" >\n");
+       }
+       put_dev_sector(sect);
+#endif /* CONFIG_MINIX_SUBPARTITION */
+}
+
+static struct {
+       unsigned char id;
+       void (*parse)(struct gendisk *, struct block_device *, int, int *);
+} subtypes[] = {
+       {BSD_PARTITION, bsd_partition},
+       {NETBSD_PARTITION, netbsd_partition},
+       {OPENBSD_PARTITION, openbsd_partition},
+       {MINIX_PARTITION, minix_partition},
+       {UNIXWARE_PARTITION, unixware_partition},
+       {SOLARIS_X86_PARTITION, solaris_x86_partition},
+       {0, NULL},
+};
+/*
+ * Look for various forms of IDE disk geometry translation
+ */
+static int handle_ide_mess(struct block_device *bdev)
+{
+#ifdef CONFIG_BLK_DEV_IDE
+       Sector sect;
+       unsigned char *data;
+       kdev_t dev = to_kdev_t(bdev->bd_dev);
+       unsigned int sig;
+       int heads = 0;
+       struct partition *p;
+       int i;
+
+       if (MSDOS_DEBUG)
+         printk (KERN_ALERT "handle_ide_mess ------------\n");
+
+       /*
+        * The i386 partition handling programs very often
+        * make partitions end on cylinder boundaries.
+        * There is no need to do so, and Linux fdisk doesnt always
+        * do this, and Windows NT on Alpha doesnt do this either,
+        * but still, this helps to guess #heads.
+        */
+       data = read_dev_sector(bdev, 0, &sect);
+       if (!data)
+               return -1;
+       if (!msdos_magic_present(data + 510)) {
+               put_dev_sector(sect);
+               return 0;
+       }
+       sig = le16_to_cpu(*(unsigned short *)(data + 2));
+       p = (struct partition *) (data + 0x1be);
+       for (i = 0; i < 4; i++) {
+               struct partition *q = &p[i];
+               if (NR_SECTS(q)) {
+                       if ((q->sector & 63) == 1 &&
+                           (q->end_sector & 63) == 63)
+                               heads = q->end_head + 1;
+                       break;
+               }
+       }
+       if (SYS_IND(p) == EZD_PARTITION) {
+               /*
+                * Accesses to sector 0 must go to sector 1 instead.
+                */
+               if (ide_xlate_1024(dev, -1, heads, " [EZD]"))
+                       goto reread;
+       } else if (SYS_IND(p) == DM6_PARTITION) {
+
+               /*
+                * Everything on the disk is offset by 63 sectors,
+                * including a "new" MBR with its own partition table.
+                */
+               if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]"))
+                       goto reread;
+       } else if (sig <= 0x1ae &&
+                  data[sig] == 0xAA && data[sig+1] == 0x55 &&
+                  (data[sig+2] & 1)) {
+               /* DM6 signature in MBR, courtesy of OnTrack */
+               (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]");
+       } else if (SYS_IND(p) == DM6_AUX1PARTITION ||
+                  SYS_IND(p) == DM6_AUX3PARTITION) {
+               /*
+                * DM6 on other than the first (boot) drive
+                */
+               (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]");
+       } else {
+               (void) ide_xlate_1024(dev, 2, heads, " [PTBL]");
+       }
+       put_dev_sector(sect);
+
+       if (MSDOS_DEBUG)
+         printk (KERN_ALERT "handle_ide_mess -------- %d\n", heads);
+       return 1;
+
+reread:
+       put_dev_sector(sect);
+       /* Flush the cache */
+       invalidate_bdev(bdev, 1);
+       truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
+#endif /* CONFIG_BLK_DEV_IDE */
+       return 1;
+}
+int msdos_partition(struct gendisk *hd, struct block_device *bdev,
+                   unsigned long first_sector, int first_part_minor)
+{
+       int i, minor = first_part_minor;
+       Sector sect;
+       struct partition *p;
+       unsigned char *data;
+       int mask = (1 << hd->minor_shift) - 1;
+       int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512;
+       int current_minor = first_part_minor;
+       int err;
+
+  if (MSDOS_DEBUG) printk (KERN_ALERT "msdos.c::msdos_partition\n");
+       err = handle_ide_mess(bdev);
+       if (err <= 0)
+               return err;
+       data = read_dev_sector(bdev, 0, &sect);
+       if (!data)
+               return -1;
+       if (!msdos_magic_present(data + 510)) {
+               put_dev_sector(sect);
+               return 0;
+       }
+       p = (struct partition *) (data + 0x1be);
+
+       /*
+        * Look for partitions in two passes:
+        * First find the primary and DOS-type extended partitions.
+        * On the second pass look inside *BSD, Unixware and Solaris partitions.
+        */
+
+       current_minor += 4;
+       for (i=1 ; i<=4 ; minor++,i++,p++) {
+               if (!NR_SECTS(p))
+                       continue;
+               add_gd_partition(hd, minor,
+                               first_sector+START_SECT(p)*sector_size,
+                               NR_SECTS(p)*sector_size);
+#if CONFIG_BLK_DEV_MD
+               if (SYS_IND(p) == LINUX_RAID_PARTITION) {
+                       md_autodetect_dev(MKDEV(hd->major,minor));
+               }
+#endif
+               if (is_extended_partition(p)) {
+                       unsigned long size = hd->part[minor].nr_sects;
+                       printk(" <");
+                       /* prevent someone doing mkfs or mkswap on an
+                          extended partition, but leave room for LILO */
+                       if (size > 2)
+                               hd->part[minor].nr_sects = 2;
+                       extended_partition(hd, bdev, minor, size, &current_minor);
+                       printk(" >");
+               }
+       }
+
+       /*
+        *  Check for old-style Disk Manager partition table
+        */
+       if (msdos_magic_present(data + 0xfc)) {
+               p = (struct partition *) (0x1be + data);
+               for (i = 4 ; i < 16 ; i++, current_minor++) {
+                       p--;
+                       if ((current_minor & mask) == 0)
+                               break;
+                       if (!(START_SECT(p) && NR_SECTS(p)))
+                               continue;
+                       add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
+               }
+       }
+       printk("\n");
+
+       /* second pass - output for each on a separate line */
+       minor -= 4;
+       p = (struct partition *) (0x1be + data);
+       for (i=1 ; i<=4 ; minor++,i++,p++) {
+               unsigned char id = SYS_IND(p);
+               int n;
+
+               if (!NR_SECTS(p))
+                       continue;
+
+               for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
+                       ;
+
+               if (subtypes[n].parse)
+                       subtypes[n].parse(hd, bdev, minor, &current_minor);
+       }
+       put_dev_sector(sect);
+       return 1;
+}
diff --git a/xenolinux-2.4.16-sparse/include/linux/blk.h b/xenolinux-2.4.16-sparse/include/linux/blk.h
new file mode 100644 (file)
index 0000000..12eb99f
--- /dev/null
@@ -0,0 +1,416 @@
+#ifndef _BLK_H
+#define _BLK_H
+
+#include <linux/blkdev.h>
+#include <linux/locks.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+
+/*
+ * Spinlock for protecting the request queue which
+ * is mucked around with in interrupts on potentially
+ * multiple CPU's..
+ */
+extern spinlock_t io_request_lock;
+
+/*
+ * Initialization functions.
+ */
+extern int isp16_init(void);
+extern int cdu31a_init(void);
+extern int acsi_init(void);
+extern int mcd_init(void);
+extern int mcdx_init(void);
+extern int sbpcd_init(void);
+extern int aztcd_init(void);
+extern int sony535_init(void);
+extern int gscd_init(void);
+extern int cm206_init(void);
+extern int optcd_init(void);
+extern int sjcd_init(void);
+extern int cdi_init(void);
+extern int hd_init(void);
+extern int ide_init(void);
+extern int xd_init(void);
+extern int mfm_init(void);
+extern int loop_init(void);
+extern int md_init(void);
+extern int ap_init(void);
+extern int ddv_init(void);
+extern int z2_init(void);
+extern int swim3_init(void);
+extern int swimiop_init(void);
+extern int amiga_floppy_init(void);
+extern int atari_floppy_init(void);
+extern int ez_init(void);
+extern int bpcd_init(void);
+extern int ps2esdi_init(void);
+extern int jsfd_init(void);
+extern int viodasd_init(void);
+extern int viocd_init(void);
+extern int xlblk_init(void);
+
+#if defined(CONFIG_ARCH_S390)
+extern int dasd_init(void);
+extern int xpram_init(void);
+extern int tapeblock_init(void);
+#endif /* CONFIG_ARCH_S390 */
+
+extern void set_device_ro(kdev_t dev,int flag);
+void add_blkdev_randomness(int major);
+
+extern int floppy_init(void);
+extern void rd_load(void);
+extern int rd_init(void);
+extern int rd_doload;          /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt;          /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start;     /* starting block # of image */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */
+
+extern unsigned long initrd_start,initrd_end;
+extern int mount_initrd; /* zero if initrd should not be mounted */
+extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */
+void initrd_init(void);
+
+#endif
+
+                
+/*
+ * end_request() and friends. Must be called with the request queue spinlock
+ * acquired. All functions called within end_request() _must_be_ atomic.
+ *
+ * Several drivers define their own end_request and call
+ * end_that_request_first() and end_that_request_last()
+ * for parts of the original function. This prevents
+ * code duplication in drivers.
+ */
+
+static inline void blkdev_dequeue_request(struct request * req)
+{
+       list_del(&req->queue);
+}
+
+int end_that_request_first(struct request *req, int uptodate, char *name);
+void end_that_request_last(struct request *req);
+
+#if defined(MAJOR_NR) || defined(IDE_DRIVER)
+
+#undef DEVICE_ON
+#undef DEVICE_OFF
+
+/*
+ * Add entries as needed.
+ */
+
+#ifdef IDE_DRIVER
+
+#define DEVICE_NR(device)      (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NAME "ide"
+
+#elif (MAJOR_NR == RAMDISK_MAJOR)
+
+/* ram disk */
+#define DEVICE_NAME "ramdisk"
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NO_RANDOM
+
+#elif (MAJOR_NR == Z2RAM_MAJOR)
+
+/* Zorro II Ram */
+#define DEVICE_NAME "Z2RAM"
+#define DEVICE_REQUEST do_z2_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == FLOPPY_MAJOR)
+
+static void floppy_off(unsigned int nr);
+
+#define DEVICE_NAME "floppy"
+#define DEVICE_INTR do_floppy
+#define DEVICE_REQUEST do_fd_request
+#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
+#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
+
+#elif (MAJOR_NR == HD_MAJOR)
+
+/* Hard disk:  timeout is 6 seconds. */
+#define DEVICE_NAME "hard disk"
+#define DEVICE_INTR do_hd
+#define TIMEOUT_VALUE (6*HZ)
+#define DEVICE_REQUEST do_hd_request
+#define DEVICE_NR(device) (MINOR(device)>>6)
+
+#elif (SCSI_DISK_MAJOR(MAJOR_NR))
+
+#define DEVICE_NAME "scsidisk"
+#define TIMEOUT_VALUE (2*HZ)
+#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+
+/* Kludge to use the same number for both char and block major numbers */
+#elif  (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
+
+#define DEVICE_NAME "Multiple devices driver"
+#define DEVICE_REQUEST do_md_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == SCSI_TAPE_MAJOR)
+
+#define DEVICE_NAME "scsitape"
+#define DEVICE_INTR do_st  
+#define DEVICE_NR(device) (MINOR(device) & 0x7f)
+
+#elif (MAJOR_NR == OSST_MAJOR)
+
+#define DEVICE_NAME "onstream" 
+#define DEVICE_INTR do_osst
+#define DEVICE_NR(device) (MINOR(device) & 0x7f) 
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device) 
+
+#elif (MAJOR_NR == SCSI_CDROM_MAJOR)
+
+#define DEVICE_NAME "CD-ROM"
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == XT_DISK_MAJOR)
+
+#define DEVICE_NAME "xt disk"
+#define DEVICE_REQUEST do_xd_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+
+#elif (MAJOR_NR == PS2ESDI_MAJOR)
+
+#define DEVICE_NAME "PS/2 ESDI"
+#define DEVICE_REQUEST do_ps2esdi_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+
+#elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
+
+#define DEVICE_NAME "CDU31A"
+#define DEVICE_REQUEST do_cdu31a_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE))
+
+#define DEVICE_NAME "ACSI"
+#define DEVICE_INTR do_acsi
+#define DEVICE_REQUEST do_acsi_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+
+#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
+
+#define DEVICE_NAME "Mitsumi CD-ROM"
+/* #define DEVICE_INTR do_mcd */
+#define DEVICE_REQUEST do_mcd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
+
+#define DEVICE_NAME "Mitsumi CD-ROM"
+/* #define DEVICE_INTR do_mcdx */
+#define DEVICE_REQUEST do_mcdx_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #1"
+#define DEVICE_REQUEST do_sbpcd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #2"
+#define DEVICE_REQUEST do_sbpcd2_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #3"
+#define DEVICE_REQUEST do_sbpcd3_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
+
+#define DEVICE_NAME "Matsushita CD-ROM controller #4"
+#define DEVICE_REQUEST do_sbpcd4_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
+
+#define DEVICE_NAME "Aztech CD-ROM"
+#define DEVICE_REQUEST do_aztcd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == CDU535_CDROM_MAJOR)
+
+#define DEVICE_NAME "SONY-CDU535"
+#define DEVICE_INTR do_cdu535
+#define DEVICE_REQUEST do_cdu535_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
+
+#define DEVICE_NAME "Goldstar R420"
+#define DEVICE_REQUEST do_gscd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == CM206_CDROM_MAJOR)
+#define DEVICE_NAME "Philips/LMS CD-ROM cm206"
+#define DEVICE_REQUEST do_cm206_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
+
+#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
+#define DEVICE_REQUEST do_optcd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == SANYO_CDROM_MAJOR)
+
+#define DEVICE_NAME "Sanyo H94A CD-ROM"
+#define DEVICE_REQUEST do_sjcd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == APBLOCK_MAJOR)
+
+#define DEVICE_NAME "apblock"
+#define DEVICE_REQUEST ap_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == DDV_MAJOR)
+
+#define DEVICE_NAME "ddv"
+#define DEVICE_REQUEST ddv_request
+#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS)
+
+#elif (MAJOR_NR == MFM_ACORN_MAJOR)
+
+#define DEVICE_NAME "mfm disk"
+#define DEVICE_INTR do_mfm
+#define DEVICE_REQUEST do_mfm_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+
+#elif (MAJOR_NR == NBD_MAJOR)
+
+#define DEVICE_NAME "nbd"
+#define DEVICE_REQUEST do_nbd_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == MDISK_MAJOR)
+
+#define DEVICE_NAME "mdisk"
+#define DEVICE_REQUEST mdisk_request
+#define DEVICE_NR(device) (MINOR(device))
+
+#elif (MAJOR_NR == DASD_MAJOR)
+
+#define DEVICE_NAME "dasd"
+#define DEVICE_REQUEST do_dasd_request
+#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+
+#elif (MAJOR_NR == I2O_MAJOR)
+
+#define DEVICE_NAME "I2O block"
+#define DEVICE_REQUEST i2ob_request
+#define DEVICE_NR(device) (MINOR(device)>>4)
+
+#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
+
+#define DEVICE_NAME "ida"
+#define TIMEOUT_VALUE (25*HZ)
+#define DEVICE_REQUEST do_ida_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+
+#elif (MAJOR_NR == XLBLK_MAJOR)
+
+#define DEVICE_NAME "blk"
+#define DEVICE_REQUEST do_xlblk_request
+/* #define DEVICE_INTR */
+#define DEVICE_NR(device) (MINOR(device))
+
+#endif /* MAJOR_NR == whatever */
+
+/* provide DEVICE_xxx defaults, if not explicitly defined
+ * above in the MAJOR_NR==xxx if-elif tree */
+#ifndef DEVICE_ON
+#define DEVICE_ON(device) do {} while (0)
+#endif
+#ifndef DEVICE_OFF
+#define DEVICE_OFF(device) do {} while (0)
+#endif
+
+#if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR)
+#if !defined(IDE_DRIVER)
+
+#ifndef CURRENT
+#define CURRENT blkdev_entry_next_request(&blk_dev[MAJOR_NR].request_queue.queue_head)
+#endif
+#ifndef QUEUE_EMPTY
+#define QUEUE_EMPTY list_empty(&blk_dev[MAJOR_NR].request_queue.queue_head)
+#endif
+
+#ifndef DEVICE_NAME
+#define DEVICE_NAME "unknown"
+#endif
+
+#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev)
+
+#ifdef DEVICE_INTR
+static void (*DEVICE_INTR)(void) = NULL;
+#endif
+
+#define SET_INTR(x) (DEVICE_INTR = (x))
+
+#ifdef DEVICE_REQUEST
+static void (DEVICE_REQUEST)(request_queue_t *);
+#endif 
+  
+#ifdef DEVICE_INTR
+#define CLEAR_INTR SET_INTR(NULL)
+#else
+#define CLEAR_INTR
+#endif
+
+#define INIT_REQUEST \
+       if (QUEUE_EMPTY) {\
+               CLEAR_INTR; \
+               return; \
+       } \
+       if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \
+               panic(DEVICE_NAME ": request list destroyed"); \
+       if (CURRENT->bh) { \
+               if (!buffer_locked(CURRENT->bh)) \
+                       panic(DEVICE_NAME ": block not locked"); \
+       }
+
+#endif /* !defined(IDE_DRIVER) */
+
+
+#ifndef LOCAL_END_REQUEST      /* If we have our own end_request, we do not want to include this mess */
+
+#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR)
+
+static inline void end_request(int uptodate) {
+       struct request *req = CURRENT;
+
+       if (end_that_request_first(req, uptodate, DEVICE_NAME))
+               return;
+
+#ifndef DEVICE_NO_RANDOM
+       add_blkdev_randomness(MAJOR(req->rq_dev));
+#endif
+       DEVICE_OFF(req->rq_dev);
+       blkdev_dequeue_request(req);
+       end_that_request_last(req);
+}
+
+#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */
+#endif /* LOCAL_END_REQUEST */
+
+#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */
+#endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */
+
+#endif /* _BLK_H */
diff --git a/xenolinux-2.4.16-sparse/include/linux/major.h b/xenolinux-2.4.16-sparse/include/linux/major.h
new file mode 100644 (file)
index 0000000..820bf68
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef _LINUX_MAJOR_H
+#define _LINUX_MAJOR_H
+
+/*
+ * This file has definitions for major device numbers.
+ * For the device number assignments, see Documentation/devices.txt.
+ */
+
+/* limits */
+
+/*
+ * Important: Don't change this to 256.  Major number 255 is and must be
+ * reserved for future expansion into a larger dev_t space.
+ */
+#define MAX_CHRDEV     255
+#define MAX_BLKDEV     255
+
+#define UNNAMED_MAJOR  0
+#define MEM_MAJOR      1
+#define RAMDISK_MAJOR  1
+#define FLOPPY_MAJOR   2
+#define PTY_MASTER_MAJOR 2
+#define IDE0_MAJOR     3
+#define PTY_SLAVE_MAJOR 3
+#define HD_MAJOR       IDE0_MAJOR
+#define TTY_MAJOR      4
+#define TTYAUX_MAJOR   5
+#define LP_MAJOR       6
+#define VCS_MAJOR      7
+#define LOOP_MAJOR     7
+#define SCSI_DISK0_MAJOR 8
+#define SCSI_TAPE_MAJOR        9
+#define MD_MAJOR        9
+#define MISC_MAJOR     10
+#define SCSI_CDROM_MAJOR 11
+#define QIC02_TAPE_MAJOR 12
+#define XT_DISK_MAJOR  13
+#define SOUND_MAJOR    14
+#define CDU31A_CDROM_MAJOR 15
+#define JOYSTICK_MAJOR 15
+#define GOLDSTAR_CDROM_MAJOR 16
+#define OPTICS_CDROM_MAJOR 17
+#define SANYO_CDROM_MAJOR 18
+#define CYCLADES_MAJOR  19
+#define CYCLADESAUX_MAJOR 20
+#define MITSUMI_X_CDROM_MAJOR 20
+#define MFM_ACORN_MAJOR 21     /* ARM Linux /dev/mfm */
+#define SCSI_GENERIC_MAJOR 21
+#define Z8530_MAJOR 34
+#define DIGI_MAJOR 23
+#define IDE1_MAJOR     22
+#define DIGICU_MAJOR 22
+#define MITSUMI_CDROM_MAJOR 23
+#define CDU535_CDROM_MAJOR 24
+#define STL_SERIALMAJOR 24
+#define MATSUSHITA_CDROM_MAJOR 25
+#define STL_CALLOUTMAJOR 25
+#define MATSUSHITA_CDROM2_MAJOR 26
+#define QIC117_TAPE_MAJOR 27
+#define MATSUSHITA_CDROM3_MAJOR 27
+#define MATSUSHITA_CDROM4_MAJOR 28
+#define STL_SIOMEMMAJOR 28
+#define ACSI_MAJOR     28
+#define AZTECH_CDROM_MAJOR 29
+#define GRAPHDEV_MAJOR 29      /* SparcLinux & Linux/68k /dev/fb */
+#define SHMIQ_MAJOR    85      /* Linux/mips, SGI /dev/shmiq */
+#define CM206_CDROM_MAJOR 32
+#define IDE2_MAJOR     33
+#define IDE3_MAJOR     34
+#define XPRAM_MAJOR     35      /* expanded storage on S/390 = "slow ram" */
+                                /* proposed by Peter                      */
+#define NETLINK_MAJOR  36
+#define PS2ESDI_MAJOR  36
+#define IDETAPE_MAJOR  37
+#define Z2RAM_MAJOR    37
+#define APBLOCK_MAJOR   38   /* AP1000 Block device */
+#define DDV_MAJOR       39   /* AP1000 DDV block device */
+#define NBD_MAJOR      43   /* Network block device    */
+#define RISCOM8_NORMAL_MAJOR 48
+#define DAC960_MAJOR   48      /* 48..55 */
+#define RISCOM8_CALLOUT_MAJOR 49
+#define MKISS_MAJOR    55
+#define DSP56K_MAJOR    55   /* DSP56001 processor device */
+
+#define IDE4_MAJOR     56
+#define IDE5_MAJOR     57
+
+#define LVM_BLK_MAJOR  58      /* Logical Volume Manager */
+
+#define SCSI_DISK1_MAJOR       65
+#define SCSI_DISK2_MAJOR       66
+#define SCSI_DISK3_MAJOR       67
+#define SCSI_DISK4_MAJOR       68
+#define SCSI_DISK5_MAJOR       69
+#define SCSI_DISK6_MAJOR       70
+#define SCSI_DISK7_MAJOR       71
+
+
+#define COMPAQ_SMART2_MAJOR    72
+#define COMPAQ_SMART2_MAJOR1   73
+#define COMPAQ_SMART2_MAJOR2   74
+#define COMPAQ_SMART2_MAJOR3   75
+#define COMPAQ_SMART2_MAJOR4   76
+#define COMPAQ_SMART2_MAJOR5   77
+#define COMPAQ_SMART2_MAJOR6   78
+#define COMPAQ_SMART2_MAJOR7   79
+
+#define SPECIALIX_NORMAL_MAJOR 75
+#define SPECIALIX_CALLOUT_MAJOR 76
+
+#define COMPAQ_CISS_MAJOR      104
+#define COMPAQ_CISS_MAJOR1     105
+#define COMPAQ_CISS_MAJOR2      106
+#define COMPAQ_CISS_MAJOR3      107
+#define COMPAQ_CISS_MAJOR4      108
+#define COMPAQ_CISS_MAJOR5      109
+#define COMPAQ_CISS_MAJOR6      110
+#define COMPAQ_CISS_MAJOR7      111
+
+#define ATARAID_MAJOR          114
+
+#define DASD_MAJOR      94     /* Official assignations from Peter */
+
+#define MDISK_MAJOR     95     /* Official assignations from Peter */
+
+#define I2O_MAJOR              80      /* 80->87 */
+
+#define IDE6_MAJOR     88
+#define IDE7_MAJOR     89
+#define IDE8_MAJOR     90
+#define IDE9_MAJOR     91
+
+#define UBD_MAJOR      98
+
+#define AURORA_MAJOR 79
+
+#define JSFD_MAJOR     99
+
+#define PHONE_MAJOR    100
+
+#define LVM_CHAR_MAJOR 109     /* Logical Volume Manager */
+
+#define        UMEM_MAJOR      116     /* http://www.umem.com/ Battery Backed RAM */
+
+#define XLBLK_MAJOR    123     /* XenoLinux Block Device */
+
+#define RTF_MAJOR      150
+#define RAW_MAJOR      162
+
+#define USB_ACM_MAJOR          166
+#define USB_ACM_AUX_MAJOR      167
+#define USB_CHAR_MAJOR         180
+
+#define UNIX98_PTY_MASTER_MAJOR        128
+#define UNIX98_PTY_MAJOR_COUNT 8
+#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
+
+#define VXVM_MAJOR             199     /* VERITAS volume i/o driver    */
+#define VXSPEC_MAJOR           200     /* VERITAS volume config driver */
+#define VXDMP_MAJOR            201     /* VERITAS volume multipath driver */
+
+#define MSR_MAJOR              202
+#define CPUID_MAJOR            203
+
+#define OSST_MAJOR     206     /* OnStream-SCx0 SCSI tape */
+
+#define IBM_TTY3270_MAJOR       227    /* Official allocations now */
+#define IBM_FS3270_MAJOR        228
+
+/*
+ * Tests for SCSI devices.
+ */
+
+#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \
+  ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR))
+  
+#define SCSI_BLK_MAJOR(M) \
+  (SCSI_DISK_MAJOR(M)  \
+   || (M) == SCSI_CDROM_MAJOR)
+
+static __inline__ int scsi_blk_major(int m) {
+       return SCSI_BLK_MAJOR(m);
+}
+
+/*
+ * Tests for IDE devices
+ */
+#define IDE_DISK_MAJOR(M)      ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \
+                               (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \
+                               (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \
+                               (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \
+                               (M) == IDE8_MAJOR || (M) == IDE9_MAJOR)
+
+static __inline__ int ide_blk_major(int m)
+{
+       return IDE_DISK_MAJOR(m);
+}
+
+#endif
diff --git a/xenolinux-2.4.16-sparse/init/main.c b/xenolinux-2.4.16-sparse/init/main.c
new file mode 100644 (file)
index 0000000..a48a777
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ *  linux/init/main.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  GK 2/5/95  -  Changed to support mounting root fs via NFS
+ *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
+ *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
+ *  Simplified starting of init:  Michael A. Griffith <grif@acm.org> 
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/config.h>
+#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/unistd.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/utsname.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/blk.h>
+#include <linux/hdreg.h>
+#include <linux/iobuf.h>
+#include <linux/bootmem.h>
+#include <linux/tty.h>
+
+#include <asm/io.h>
+#include <asm/bugs.h>
+
+#if defined(CONFIG_ARCH_S390)
+#include <asm/s390mach.h>
+#include <asm/ccwcache.h>
+#endif
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_DIO
+#include <linux/dio.h>
+#endif
+
+#ifdef CONFIG_ZORRO
+#include <linux/zorro.h>
+#endif
+
+#ifdef CONFIG_MTRR
+#  include <asm/mtrr.h>
+#endif
+
+#ifdef CONFIG_NUBUS
+#include <linux/nubus.h>
+#endif
+
+#ifdef CONFIG_ISAPNP
+#include <linux/isapnp.h>
+#endif
+
+#ifdef CONFIG_IRDA
+extern int irda_proto_init(void);
+extern int irda_device_init(void);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/smp.h>
+#endif
+
+#if defined(CONFIG_KDB)
+#include <linux/kdb.h>
+#endif
+
+/*
+ * Versions of gcc older than that listed below may actually compile
+ * and link okay, but the end product can have subtle run time bugs.
+ * To avoid associated bogus bug reports, we flatly refuse to compile
+ * with a gcc that is known to be too old from the very beginning.
+ */
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91)
+#error Sorry, your GCC is too old. It builds incorrect kernels.
+#endif
+
+extern char _stext, _etext;
+extern char *linux_banner;
+
+static int init(void *);
+
+extern void init_IRQ(void);
+extern void init_modules(void);
+extern void sock_init(void);
+extern void fork_init(unsigned long);
+extern void mca_init(void);
+extern void sbus_init(void);
+extern void ppc_init(void);
+extern void sysctl_init(void);
+extern void signals_init(void);
+extern int init_pcmcia_ds(void);
+
+extern void free_initmem(void);
+
+#ifdef CONFIG_TC
+extern void tc_init(void);
+#endif
+
+extern void ecard_init(void);
+
+#if defined(CONFIG_SYSVIPC)
+extern void ipc_init(void);
+#endif
+
+/*
+ * Boot command-line arguments
+ */
+#define MAX_INIT_ARGS 8
+#define MAX_INIT_ENVS 8
+
+extern void time_init(void);
+extern void softirq_init(void);
+
+int rows, cols;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+unsigned int real_root_dev;    /* do_proc_dointvec cannot handle kdev_t */
+#endif
+
+int root_mountflags = MS_RDONLY;
+char *execute_command;
+char root_device_name[64];
+
+
+static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
+static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+
+static int __init profile_setup(char *str)
+{
+    int par;
+    if (get_option(&str,&par)) prof_shift = par;
+       return 1;
+}
+
+__setup("profile=", profile_setup);
+
+
+static struct dev_name_struct {
+       const char *name;
+       const int num;
+} root_dev_names[] __initdata = {
+       { "nfs",     0x00ff },
+        { "blk",     0x7b00 },
+       { "hda",     0x0300 },
+       { "hdb",     0x0340 },
+       { "loop",    0x0700 },
+       { "hdc",     0x1600 },
+       { "hdd",     0x1640 },
+       { "hde",     0x2100 },
+       { "hdf",     0x2140 },
+       { "hdg",     0x2200 },
+       { "hdh",     0x2240 },
+       { "hdi",     0x3800 },
+       { "hdj",     0x3840 },
+       { "hdk",     0x3900 },
+       { "hdl",     0x3940 },
+       { "hdm",     0x5800 },
+       { "hdn",     0x5840 },
+       { "hdo",     0x5900 },
+       { "hdp",     0x5940 },
+       { "hdq",     0x5A00 },
+       { "hdr",     0x5A40 },
+       { "hds",     0x5B00 },
+       { "hdt",     0x5B40 },
+       { "sda",     0x0800 },
+       { "sdb",     0x0810 },
+       { "sdc",     0x0820 },
+       { "sdd",     0x0830 },
+       { "sde",     0x0840 },
+       { "sdf",     0x0850 },
+       { "sdg",     0x0860 },
+       { "sdh",     0x0870 },
+       { "sdi",     0x0880 },
+       { "sdj",     0x0890 },
+       { "sdk",     0x08a0 },
+       { "sdl",     0x08b0 },
+       { "sdm",     0x08c0 },
+       { "sdn",     0x08d0 },
+       { "sdo",     0x08e0 },
+       { "sdp",     0x08f0 },
+       { "ada",     0x1c00 },
+       { "adb",     0x1c10 },
+       { "adc",     0x1c20 },
+       { "add",     0x1c30 },
+       { "ade",     0x1c40 },
+       { "fd",      0x0200 },
+       { "md",      0x0900 },       
+       { "xda",     0x0d00 },
+       { "xdb",     0x0d40 },
+       { "ram",     0x0100 },
+       { "scd",     0x0b00 },
+       { "mcd",     0x1700 },
+       { "cdu535",  0x1800 },
+       { "sonycd",  0x1800 },
+       { "aztcd",   0x1d00 },
+       { "cm206cd", 0x2000 },
+       { "gscd",    0x1000 },
+       { "sbpcd",   0x1900 },
+       { "eda",     0x2400 },
+       { "edb",     0x2440 },
+       { "pda",        0x2d00 },
+       { "pdb",        0x2d10 },
+       { "pdc",        0x2d20 },
+       { "pdd",        0x2d30 },
+       { "pcd",        0x2e00 },
+       { "pf",         0x2f00 },
+       { "apblock", APBLOCK_MAJOR << 8},
+       { "ddv", DDV_MAJOR << 8},
+       { "jsfd",    JSFD_MAJOR << 8},
+#if defined(CONFIG_ARCH_S390)
+       { "dasda", (DASD_MAJOR << MINORBITS) },
+       { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) },
+       { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) },
+       { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) },
+       { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) },
+       { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) },
+       { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) },
+       { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
+#endif
+#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
+       { "ida/c0d0p",0x4800 },
+       { "ida/c0d1p",0x4810 },
+       { "ida/c0d2p",0x4820 },
+       { "ida/c0d3p",0x4830 },
+       { "ida/c0d4p",0x4840 },
+       { "ida/c0d5p",0x4850 },
+       { "ida/c0d6p",0x4860 },
+       { "ida/c0d7p",0x4870 },
+       { "ida/c0d8p",0x4880 },
+       { "ida/c0d9p",0x4890 },
+       { "ida/c0d10p",0x48A0 },
+       { "ida/c0d11p",0x48B0 },
+       { "ida/c0d12p",0x48C0 },
+       { "ida/c0d13p",0x48D0 },
+       { "ida/c0d14p",0x48E0 },
+       { "ida/c0d15p",0x48F0 },
+#endif
+#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE)
+       { "cciss/c0d0p",0x6800 },
+       { "cciss/c0d1p",0x6810 },
+       { "cciss/c0d2p",0x6820 },
+       { "cciss/c0d3p",0x6830 },
+       { "cciss/c0d4p",0x6840 },
+       { "cciss/c0d5p",0x6850 },
+       { "cciss/c0d6p",0x6860 },
+       { "cciss/c0d7p",0x6870 },
+       { "cciss/c0d8p",0x6880 },
+       { "cciss/c0d9p",0x6890 },
+       { "cciss/c0d10p",0x68A0 },
+       { "cciss/c0d11p",0x68B0 },
+       { "cciss/c0d12p",0x68C0 },
+       { "cciss/c0d13p",0x68D0 },
+       { "cciss/c0d14p",0x68E0 },
+       { "cciss/c0d15p",0x68F0 },
+#endif
+       { "nftla", 0x5d00 },
+       { "nftlb", 0x5d10 },
+       { "nftlc", 0x5d20 },
+       { "nftld", 0x5d30 },
+       { "ftla", 0x2c00 },
+       { "ftlb", 0x2c08 },
+       { "ftlc", 0x2c10 },
+       { "ftld", 0x2c18 },
+       { "mtdblock", 0x1f00 },
+       { NULL, 0 }
+};
+
+kdev_t __init name_to_kdev_t(char *line)
+{
+       int base = 0;
+
+       if (strncmp(line,"/dev/",5) == 0) {
+               struct dev_name_struct *dev = root_dev_names;
+               line += 5;
+               do {
+                       int len = strlen(dev->name);
+                       if (strncmp(line,dev->name,len) == 0) {
+                               line += len;
+                               base = dev->num;
+                               break;
+                       }
+                       dev++;
+               } while (dev->name);
+       }
+       return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16));
+}
+
+static int __init root_dev_setup(char *line)
+{
+       int i;
+       char ch;
+
+       ROOT_DEV = name_to_kdev_t(line);
+       memset (root_device_name, 0, sizeof root_device_name);
+       if (strncmp (line, "/dev/", 5) == 0) line += 5;
+       for (i = 0; i < sizeof root_device_name - 1; ++i)
+       {
+           ch = line[i];
+           if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break;
+           root_device_name[i] = ch;
+       }
+       return 1;
+}
+
+__setup("root=", root_dev_setup);
+
+static int __init checksetup(char *line)
+{
+       struct kernel_param *p;
+
+       p = &__setup_start;
+       do {
+               int n = strlen(p->str);
+               if (!strncmp(line,p->str,n)) {
+                       if (p->setup_func(line+n))
+                               return 1;
+               }
+               p++;
+       } while (p < &__setup_end);
+       return 0;
+}
+
+/* this should be approx 2 Bo*oMips to start (note initial shift), and will
+   still work even if initially too large, it will just take slightly longer */
+unsigned long loops_per_jiffy = (1<<12);
+
+/* This is the number of bits of precision for the loops_per_jiffy.  Each
+   bit takes on average 1.5/HZ seconds.  This (like the original) is a little
+   better than 1% */
+#define LPS_PREC 8
+
+void __init calibrate_delay(void)
+{
+       unsigned long ticks, loopbit;
+       int lps_precision = LPS_PREC;
+
+       loops_per_jiffy = (1<<12);
+
+       printk("Calibrating delay loop... ");
+       while (loops_per_jiffy <<= 1) {
+               /* wait for "start of" clock tick */
+               ticks = jiffies;
+               while (ticks == jiffies)
+                       /* nothing */;
+               /* Go .. */
+               ticks = jiffies;
+               __delay(loops_per_jiffy);
+               ticks = jiffies - ticks;
+               if (ticks)
+                       break;
+       }
+
+/* Do a binary approximation to get loops_per_jiffy set to equal one clock
+   (up to lps_precision bits) */
+       loops_per_jiffy >>= 1;
+       loopbit = loops_per_jiffy;
+       while ( lps_precision-- && (loopbit >>= 1) ) {
+               loops_per_jiffy |= loopbit;
+               ticks = jiffies;
+               while (ticks == jiffies);
+               ticks = jiffies;
+               __delay(loops_per_jiffy);
+               if (jiffies != ticks)   /* longer than 1 tick */
+                       loops_per_jiffy &= ~loopbit;
+       }
+
+/* Round the value and print it */     
+       printk("%lu.%02lu BogoMIPS\n",
+               loops_per_jiffy/(500000/HZ),
+               (loops_per_jiffy/(5000/HZ)) % 100);
+}
+
+static int __init readonly(char *str)
+{
+       if (*str)
+               return 0;
+       root_mountflags |= MS_RDONLY;
+       return 1;
+}
+
+static int __init readwrite(char *str)
+{
+       if (*str)
+               return 0;
+       root_mountflags &= ~MS_RDONLY;
+       return 1;
+}
+
+static int __init debug_kernel(char *str)
+{
+       if (*str)
+               return 0;
+       console_loglevel = 10;
+       return 1;
+}
+
+static int __init quiet_kernel(char *str)
+{
+       if (*str)
+               return 0;
+       console_loglevel = 4;
+       return 1;
+}
+
+__setup("ro", readonly);
+__setup("rw", readwrite);
+__setup("debug", debug_kernel);
+__setup("quiet", quiet_kernel);
+
+/*
+ * This is a simple kernel command line parsing function: it parses
+ * the command line, and fills in the arguments/environment to init
+ * as appropriate. Any cmd-line option is taken to be an environment
+ * variable if it contains the character '='.
+ *
+ * This routine also checks for options meant for the kernel.
+ * These options are not given to init - they are for internal kernel use only.
+ */
+static void __init parse_options(char *line)
+{
+       char *next,*quote;
+       int args, envs;
+
+       if (!*line)
+               return;
+       args = 0;
+       envs = 1;       /* TERM is set to 'linux' by default */
+       next = line;
+       while ((line = next) != NULL) {
+                quote = strchr(line,'"');
+                next = strchr(line, ' ');
+                while (next != NULL && quote != NULL && quote < next) {
+                        /* we found a left quote before the next blank
+                         * now we have to find the matching right quote
+                         */
+                        next = strchr(quote+1, '"');
+                        if (next != NULL) {
+                                quote = strchr(next+1, '"');
+                                next = strchr(next+1, ' ');
+                        }
+                }
+                if (next != NULL)
+                        *next++ = 0;
+#if defined(CONFIG_KDB)
+               /* kdb, kdb=on, kdb=off, kdb=early */
+               if (strncmp(line, "kdb", 3) == 0) {
+                       if (line[3] == '\0') {
+                               /* Backward compatibility, kdb with no option means early activation */
+                               printk("Boot flag kdb with no options is obsolete, use kdb=early\n");
+                               kdb_on = 1;
+                               kdb_flags |= KDB_FLAG_EARLYKDB;
+                               continue;
+                       }
+                       if (line[3] == '=') {
+                               if (strcmp(line+4, "on") == 0) {
+                                       kdb_on = 1;
+                                       continue;
+                               }
+                               if (strcmp(line+4, "off") == 0) {
+                                       kdb_on = 0;
+                                       continue;
+                               }
+                               if (strcmp(line+4, "early") == 0) {
+                                       kdb_on = 1;
+                                       kdb_flags |= KDB_FLAG_EARLYKDB;
+                                       continue;
+                               }
+                               printk("Boot flag %s not recognised, assumed to be environment variable\n", line);
+                       }
+               }
+#endif
+               if (!strncmp(line,"init=",5)) {
+                       line += 5;
+                       execute_command = line;
+                       /* In case LILO is going to boot us with default command line,
+                        * it prepends "auto" before the whole cmdline which makes
+                        * the shell think it should execute a script with such name.
+                        * So we ignore all arguments entered _before_ init=... [MJ]
+                        */
+                       args = 0;
+                       continue;
+               }
+               if (checksetup(line))
+                       continue;
+               
+               /*
+                * Then check if it's an environment variable or
+                * an option.
+                */
+               if (strchr(line,'=')) {
+                       if (envs >= MAX_INIT_ENVS)
+                               break;
+                       envp_init[++envs] = line;
+               } else {
+                       if (args >= MAX_INIT_ARGS)
+                               break;
+                       if (*line)
+                               argv_init[++args] = line;
+               }
+       }
+       argv_init[args+1] = NULL;
+       envp_init[envs+1] = NULL;
+}
+
+
+extern void setup_arch(char **);
+extern void cpu_idle(void);
+
+unsigned long wait_init_idle;
+
+#ifndef CONFIG_SMP
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static void __init smp_init(void)
+{
+       APIC_init_uniprocessor();
+}
+#else
+#define smp_init()     do { } while (0)
+#endif
+
+#else
+
+
+/* Called by boot processor to activate the rest. */
+static void __init smp_init(void)
+{
+       /* Get other processors into their bootup holding patterns. */
+       smp_boot_cpus();
+       wait_init_idle = cpu_online_map;
+       clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */
+
+       smp_threads_ready=1;
+       smp_commence();
+
+       /* Wait for the other cpus to set up their idle processes */
+       printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle);
+       while (wait_init_idle) {
+               cpu_relax();
+               barrier();
+       }
+       printk("All processors have done init_idle\n");
+}
+
+#endif
+
+/*
+ * We need to finalize in a non-__init function or else race conditions
+ * between the root thread and the init thread may cause start_kernel to
+ * be reaped by free_initmem before the root thread has proceeded to
+ * cpu_idle.
+ */
+
+static void rest_init(void)
+{
+       kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
+       unlock_kernel();
+       current->need_resched = 1;
+       cpu_idle();
+} 
+
+/*
+ *     Activate the first processor.
+ */
+
+asmlinkage void __init start_kernel(void)
+{
+       char * command_line;
+       unsigned long mempages;
+       extern char saved_command_line[];
+/*
+ * Interrupts are still disabled. Do necessary setups, then
+ * enable them
+ */
+       lock_kernel();
+       printk(linux_banner);
+       setup_arch(&command_line);
+       printk("Kernel command line: %s\n", saved_command_line);
+       parse_options(command_line);
+       trap_init();
+       init_IRQ();
+       sched_init();
+       softirq_init();
+       time_init();
+
+       /*
+        * HACK ALERT! This is early. We're enabling the console before
+        * we've done PCI setups etc, and console_init() must be aware of
+        * this. But we do want output early, in case something goes wrong.
+        */
+       console_init();
+#ifdef CONFIG_MODULES
+       init_modules();
+#endif
+       if (prof_shift) {
+               unsigned int size;
+               /* only text is profiled */
+               prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
+               prof_len >>= prof_shift;
+               
+               size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1;
+               prof_buffer = (unsigned int *) alloc_bootmem(size);
+       }
+
+       kmem_cache_init();
+       sti();
+       calibrate_delay();
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start && !initrd_below_start_ok &&
+                       initrd_start < min_low_pfn << PAGE_SHIFT) {
+               printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
+                   "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
+               initrd_start = 0;
+       }
+#endif
+       mem_init();
+       kmem_cache_sizes_init();
+#if defined(CONFIG_KDB)
+       kdb_init();
+       if (KDB_FLAG(EARLYKDB)) {
+               KDB_ENTER();
+       }
+#endif
+       mempages = num_physpages;
+
+       fork_init(mempages);
+       proc_caches_init();
+       vfs_caches_init(mempages);
+       buffer_init(mempages);
+       page_cache_init(mempages);
+#if defined(CONFIG_ARCH_S390)
+       ccwcache_init();
+#endif
+       signals_init();
+#ifdef CONFIG_PROC_FS
+       proc_root_init();
+#endif
+#if defined(CONFIG_SYSVIPC)
+       ipc_init();
+#endif
+       check_bugs();
+       printk("POSIX conformance testing by UNIFIX\n");
+
+       /* 
+        *      We count on the initial thread going ok 
+        *      Like idlers init is an unlocked kernel thread, which will
+        *      make syscalls (and thus be locked).
+        */
+       smp_init();
+       rest_init();
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+static int do_linuxrc(void * shell)
+{
+       static char *argv[] = { "linuxrc", NULL, };
+
+       close(0);close(1);close(2);
+       setsid();
+       (void) open("/dev/console",O_RDWR,0);
+       (void) dup(0);
+       (void) dup(0);
+       return execve(shell, argv, envp_init);
+}
+
+#endif
+
+struct task_struct *child_reaper = &init_task;
+
+static void __init do_initcalls(void)
+{
+       initcall_t *call;
+
+       call = &__initcall_start;
+       do {
+               (*call)();
+               call++;
+       } while (call < &__initcall_end);
+
+       /* Make sure there is no pending stuff from the initcall sequence */
+       flush_scheduled_tasks();
+}
+
+/*
+ * Ok, the machine is now initialized. None of the devices
+ * have been touched yet, but the CPU subsystem is up and
+ * running, and memory and process management works.
+ *
+ * Now we can finally start doing some real work..
+ */
+static void __init do_basic_setup(void)
+{
+
+       /*
+        * Tell the world that we're going to be the grim
+        * reaper of innocent orphaned children.
+        *
+        * We don't want people to have to make incorrect
+        * assumptions about where in the task array this
+        * can be found.
+        */
+       child_reaper = current;
+
+#if defined(CONFIG_MTRR)       /* Do this after SMP initialization */
+/*
+ * We should probably create some architecture-dependent "fixup after
+ * everything is up" style function where this would belong better
+ * than in init/main.c..
+ */
+       mtrr_init();
+#endif
+
+#ifdef CONFIG_SYSCTL
+       sysctl_init();
+#endif
+
+       /*
+        * Ok, at this point all CPU's should be initialized, so
+        * we can start looking into devices..
+        */
+#if defined(CONFIG_ARCH_S390)
+       s390_init_machine_check();
+#endif
+
+#ifdef CONFIG_PCI
+       pci_init();
+#endif
+#ifdef CONFIG_SBUS
+       sbus_init();
+#endif
+#if defined(CONFIG_PPC)
+       ppc_init();
+#endif
+#ifdef CONFIG_MCA
+       mca_init();
+#endif
+#ifdef CONFIG_ARCH_ACORN
+       ecard_init();
+#endif
+#ifdef CONFIG_ZORRO
+       zorro_init();
+#endif
+#ifdef CONFIG_DIO
+       dio_init();
+#endif
+#ifdef CONFIG_NUBUS
+       nubus_init();
+#endif
+#ifdef CONFIG_ISAPNP
+       isapnp_init();
+#endif
+#ifdef CONFIG_TC
+       tc_init();
+#endif
+
+       /* Networking initialization needs a process context */ 
+       sock_init();
+
+       start_context_thread();
+       do_initcalls();
+
+#ifdef CONFIG_IRDA
+       irda_proto_init();
+       irda_device_init(); /* Must be done after protocol initialization */
+#endif
+#ifdef CONFIG_PCMCIA
+       init_pcmcia_ds();               /* Do this last */
+#endif
+}
+
+extern void rd_load(void);
+extern void initrd_load(void);
+
+/*
+ * Prepare the namespace - decide what/where to mount, load ramdisks, etc.
+ */
+static void prepare_namespace(void)
+{
+#ifdef CONFIG_BLK_DEV_INITRD
+       int real_root_mountflags = root_mountflags;
+       if (!initrd_start)
+               mount_initrd = 0;
+       if (mount_initrd)
+               root_mountflags &= ~MS_RDONLY;
+       real_root_dev = ROOT_DEV;
+#endif
+
+#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (mount_initrd)
+               initrd_load();
+       else
+#endif
+       rd_load();
+#endif
+
+       /* Mount the root filesystem.. */
+       mount_root();
+
+       mount_devfs_fs ();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       root_mountflags = real_root_mountflags;
+       if (mount_initrd && ROOT_DEV != real_root_dev
+           && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
+               int error;
+               int i, pid;
+
+               pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
+               if (pid > 0) {
+                       while (pid != wait(&i)) {
+                               current->policy |= SCHED_YIELD;
+                               schedule();
+                       }
+               }
+               if (MAJOR(real_root_dev) != RAMDISK_MAJOR
+                    || MINOR(real_root_dev) != 0) {
+                       error = change_root(real_root_dev,"/initrd");
+                       if (error)
+                               printk(KERN_ERR "Change root to /initrd: "
+                                   "error %d\n",error);
+               }
+       }
+#endif
+}
+
+static int init(void * unused)
+{
+       lock_kernel();
+       do_basic_setup();
+
+       prepare_namespace();
+
+       /*
+        * Ok, we have completed the initial bootup, and
+        * we're essentially up and running. Get rid of the
+        * initmem segments and start the user-mode stuff..
+        */
+       free_initmem();
+       unlock_kernel();
+
+       if (open("/dev/console", O_RDWR, 0) < 0)
+               printk("Warning: unable to open an initial console.\n");
+
+       (void) dup(0);
+       (void) dup(0);
+       
+       /*
+        * We try each of these until one succeeds.
+        *
+        * The Bourne shell can be used instead of init if we are 
+        * trying to recover a really broken machine.
+        */
+
+       if (execute_command)
+               execve(execute_command,argv_init,envp_init);
+       execve("/sbin/init",argv_init,envp_init);
+       execve("/etc/init",argv_init,envp_init);
+       execve("/bin/init",argv_init,envp_init);
+       execve("/bin/sh",argv_init,envp_init);
+       panic("No init found.  Try passing init= option to kernel.");
+}